├── .gitignore ├── .swiftpm └── xcode │ ├── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── daniele.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ └── daniele.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Configs ├── UAParserSwift.plist └── UAParserSwiftTests.plist ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── UAParserSwift │ └── UAParserSwift.swift ├── TestApplication ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist └── ViewController.swift ├── Tests ├── .DS_Store ├── LinuxMain.swift └── UAParserSwiftTests │ ├── UAParserSwift_Tests.swift │ ├── browser-test.json │ ├── cpu-test.json │ ├── device-test.json │ ├── engines-test.json │ └── os-test.json ├── UAParserSwift.podspec ├── UAParserSwift.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── daniele.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ ├── UAParserSwift-iOS.xcscheme │ │ ├── UAParserSwift-macOS.xcscheme │ │ ├── UAParserSwift-tvOS.xcscheme │ │ └── UAParserSwift-watchOS.xcscheme └── xcuserdata │ └── daniele.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist └── banner.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malcommac/UAParserSwift/a8057c7cff60db2cdf31d0a0a68ce430754ab64e/.swiftpm/xcode/package.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.swiftpm/xcode/xcuserdata/daniele.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | UAParserSwift.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Configs/UAParserSwift.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2017 Daniele Margutti. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Configs/UAParserSwiftTests.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Daniele Margutti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "UAParserSwift", 8 | platforms: [ 9 | .macOS(.v10_15), .iOS(.v11) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries a package produces, and make them visible to other packages. 13 | .library( 14 | name: "UAParserSwift", 15 | targets: ["UAParserSwift"]), 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 24 | .target( 25 | name: "UAParserSwift", 26 | dependencies: []), 27 | .testTarget( 28 | name: "UAParserSwiftTests", 29 | dependencies: ["UAParserSwift"]), 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | UAParserSwift 3 |

4 | 5 |

User-Agent Parser based upon ua-parser.js

6 | 7 | UAParserSwift is a Swift-based library to parse User Agent string; it's a port of [ua-parser-js](https://github.com/faisalman/ua-parser-js) by Faisal Salman created to be mainly used in Swift Server Side applications ([Kitura](http://kitura.io), [Vapor](https://opencollective.com/vapor) etc.). 8 | You can however use it on client side, all Apple's platforms are supported (iOS, macOS, tvOS and watchOS). 9 | 10 | This library aims to identify detailed type of web browser, layout engine, operating system, cpu architecture, and device type/model, entirely from user-agent string with a relatively small footprint. 11 | 12 | ## ❤️ Your Support 13 | 14 | *Hi fellow developer!* 15 | You know, maintaing and developing tools consumes resources and time. While I enjoy making them **your support is foundamental to allow me continue its development**. 16 | 17 | If you are using SwiftLocation or any other of my creations please consider the following options: 18 | 19 | - [**Make a donation with PayPal**](https://www.paypal.com/paypalme/danielemargutti/20) 20 | - [**Become a Sponsor**](https://github.com/sponsors/malcommac) 21 | 22 | - [Follow Me](https://github.com/malcommac) 23 | 24 | ## How it works 25 | 26 | * [Introduction](#doc) 27 | * [Supported Browsers](#browsers) 28 | * [Supported Devices](#devices) 29 | * [Supported Engines](#engines) 30 | * [Supported OSs](#oss) 31 | * [Supported Architectures](#architectures) 32 | 33 | * [Unit Tests](#tests) 34 | * [Installation](#installation) 35 | * [License](#license) 36 | 37 | 38 | 39 | ## Introduction 40 | 41 | Usage of UAParserSwift is pretty simple; just allocate an `UAParser` object along with the `User-Agent` string you want to parse. 42 | 43 | ```swift 44 | let parser = UAParser(agent: "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7") 45 | 46 | // Then call properties you want to read. 47 | // Parsed data are cached and evaluated lazily in order to 48 | // get the best performances. 49 | 50 | let identified_os = parser.os 51 | let identified_device = parser.device 52 | let identified_engine = parser.engine 53 | let identified_os = parser.os 54 | let identified_cpu = parser.cpu 55 | ``` 56 | 57 | Now you can call one of these properties to get parsed data (all properties are lazy created in order to keep parser lightweight): 58 | 59 | * `.browser`: return a `Browser` object with the browser's properties: `name`, `version` 60 | * `.device`: return a `Device` object with device's informations: `vendor`,`type`,`model` 61 | * `.engine`: return an `Engine` object with information about browser's engine: `name`,`version` 62 | * `.os`: return an `OS` object with the information about host operation system: `name`,`version` 63 | * `.cpu`: return a `CPU` object with the informations about host's device architecture: `identifier` 64 | 65 | 66 | 67 | ## Supported Browsers 68 | 69 | **Name**: 70 | ``` 71 | Amaya, Android Browser, Arora, Avant, Baidu, Blazer, Bolt, Bowser, Camino, Chimera, 72 | Chrome [WebView], Chromium, Comodo Dragon, Conkeror, Dillo, Dolphin, Doris, Edge, 73 | Epiphany, Fennec, Firebird, Firefox, Flock, GoBrowser, iCab, ICE Browser, IceApe, 74 | IceCat, IceDragon, Iceweasel, IE[Mobile], Iron, Jasmine, K-Meleon, Konqueror, Kindle, 75 | Links, Lunascape, Lynx, Maemo, Maxthon, Midori, Minimo, MIUI Browser, [Mobile] Safari, 76 | Mosaic, Mozilla, Netfront, Netscape, NetSurf, Nokia, OmniWeb, Opera [Mini/Mobi/Tablet], 77 | PhantomJS, Phoenix, Polaris, QQBrowser, RockMelt, Silk, Skyfire, SeaMonkey, Sleipnir, 78 | SlimBrowser, Swiftfox, Tizen, UCBrowser, Vivaldi, w3m, WeChat, Yandex 79 | ``` 80 | 81 | **Version**: 82 | Determined dynamically 83 | 84 | 85 | 86 | ## Supported Devices 87 | 88 | **Type**: 89 | 90 | ``` 91 | console, mobile, tablet, smarttv, wearable, embedded 92 | ``` 93 | 94 | **Vendor**: 95 | 96 | ``` 97 | Acer, Alcatel, Amazon, Apple, Archos, Asus, BenQ, BlackBerry, Dell, GeeksPhone, 98 | Google, HP, HTC, Huawei, Jolla, Lenovo, LG, Meizu, Microsoft, Motorola, Nexian, 99 | Nintendo, Nokia, Nvidia, OnePlus, Ouya, Palm, Panasonic, Pebble, Polytron, RIM, 100 | Samsung, Sharp, Siemens, Sony[Ericsson], Sprint, Xbox, Xiaomi, ZTE 101 | ``` 102 | 103 | **Model**: 104 | Determined dinamically 105 | 106 | 107 | 108 | ## Supported Engines 109 | 110 | **Engine**: 111 | 112 | ``` 113 | Amaya, EdgeHTML, Gecko, iCab, KHTML, Links, Lynx, NetFront, NetSurf, Presto, 114 | Tasman, Trident, w3m, WebKit 115 | ``` 116 | 117 | **Engine Version**: 118 | Determined dinamically 119 | 120 | 121 | 122 | ## Supported OSs 123 | 124 | **Name**: 125 | ``` 126 | AIX, Amiga OS, Android, Arch, Bada, BeOS, BlackBerry, CentOS, Chromium OS, Contiki, 127 | Fedora, Firefox OS, FreeBSD, Debian, DragonFly, Gentoo, GNU, Haiku, Hurd, iOS, 128 | Joli, Linpus, Linux, Mac OS, Mageia, Mandriva, MeeGo, Minix, Mint, Morph OS, NetBSD, 129 | Nintendo, OpenBSD, OpenVMS, OS/2, Palm, PC-BSD, PCLinuxOS, Plan9, Playstation, QNX, RedHat, 130 | RIM Tablet OS, RISC OS, Sailfish, Series40, Slackware, Solaris, SUSE, Symbian, Tizen, 131 | Ubuntu, UNIX, VectorLinux, WebOS, Windows [Phone/Mobile], Zenwalk 132 | ``` 133 | 134 | **Version**: 135 | Determined dinamically 136 | 137 | 138 | 139 | ## Supported Architectures 140 | 141 | **Identifier**: 142 | ``` 143 | 68k, amd64, arm[64], avr, ia[32/64], irix[64], mips[64], pa-risc, ppc, sparc[64] 144 | ``` 145 | 146 | 147 | 148 | ## Unit Tests 149 | 150 | Unit Tests are available under the [`Tests`](https://github.com/malcommac/UAParserSwift/tree/master/Tests) directory; actually they are the same tests available for ua-parser-js and all are passed successfully. 151 | 152 | 153 | 154 | ## Installation 155 | 156 | This library is written for Swift 4.x. 157 | 158 | ### Swift Package Manager (Vapor or any server side framework) 159 | 160 | Meow requires Swift 4.0 or greater to work. 161 | This is the official way to install packages for Swift Server Side. 162 | In your Package.swift, add the following to your dependencies array: 163 | 164 | ```swift 165 | .package(url: "https://github.com/malcommac/UAParserSwift.git", from: "1.0.1") 166 | ``` 167 | 168 | To your target, add the "UAParserSwift" dependency. 169 | 170 | ```swift 171 | .target(name: "Application", dependencies: ["UAParserSwift", ...]) 172 | ``` 173 | 174 | ### CocoaPods 175 | 176 | 1. Add the pod `UAParserSwift` to your [Podfile](http://guides.cocoapods.org/using/the-podfile.html). 177 | 178 | ```ruby 179 | pod 'UAParserSwift' 180 | ``` 181 | Run `pod install` from Terminal, then open your app's `.xcworkspace` file to launch Xcode. 182 | 183 | 184 | 185 | ## Contributing 186 | 187 | - If you **need help** or you'd like to **ask a general question**, open an issue. 188 | - If you **found a bug**, open an issue. 189 | - If you **have a feature request**, open an issue. 190 | - If you **want to contribute**, submit a pull request. 191 | 192 | 193 | 194 | ## License 195 | 196 | Dual licensed under GPLv2 & MIT 197 | 198 | Copyright © 2017 Daniele Margutti 199 | Original [ua-parser-js](http://faisalman.github.io/ua-parser-js) Copyright: Copyright © 2012-2016 Faisal Salman 200 | 201 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 202 | 203 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 204 | 205 | This software is licensed under [MIT License](LICENSE.md). 206 | 207 | **Consider ❤️ [support the development](#support) of this library!** 208 | 209 | ***Follow me on:*** 210 | - 💼 [Linkedin](https://www.linkedin.com/in/danielemargutti/) 211 | - 🐦 [Twitter](https://twitter.com/danielemargutti) 212 | -------------------------------------------------------------------------------- /Sources/UAParserSwift/UAParserSwift.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UAParserSwift 3 | // Lightweight Swift-based User-Agent string parser 4 | // 5 | // --------------------------------------------------- 6 | // Created by Daniele Margutti 7 | // web: http://www.danielemargutti.com 8 | // email: hello@danielemargutti.com 9 | // 10 | // Copyright © 2017 Daniele Margutti. 11 | // Dual licensed under GPLv2 & MIT 12 | // 13 | // This is a port of ua-parser.js library in Swift 14 | // Original JavaScript Version - Copyright © 2012-2016 Faisal Salman 15 | // 16 | // Permission is hereby granted, free of charge, to any person obtaining a copy 17 | // of this software and associated documentation files (the "Software"), to deal 18 | // in the Software without restriction, including without limitation the rights 19 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | // copies of the Software, and to permit persons to whom the Software is 21 | // furnished to do so, subject to the following conditions: 22 | // 23 | // The above copyright notice and this permission notice shall be included in 24 | // all copies or substantial portions of the Software. 25 | // 26 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 | // THE SOFTWARE. 33 | 34 | import Foundation 35 | 36 | /// MARK: - Parser Class 37 | 38 | public class UAParser { 39 | 40 | /// User agent raw string 41 | public private(set) var agent: String 42 | 43 | /// Initialize with user agent string 44 | /// 45 | /// - Parameter agent: user agent string 46 | public init(agent: String) { 47 | self.agent = agent 48 | } 49 | 50 | /// identified browser 51 | public lazy var browser: Browser? = { 52 | return Browser(self.parse(using: Regexes.browsers)) 53 | }() 54 | 55 | /// identified CPU 56 | public lazy var cpu: CPU? = { 57 | return CPU(self.parse(using: Regexes.cpu)) 58 | }() 59 | 60 | /// identified device 61 | public lazy var device: Device? = { 62 | return Device(self.parse(using: Regexes.device)) 63 | }() 64 | 65 | /// identified browser engine 66 | public lazy var engine: Engine? = { 67 | return Engine(self.parse(using: Regexes.engine)) 68 | }() 69 | 70 | /// identified operating system 71 | public lazy var os: OS? = { 72 | return OS(self.parse(using: Regexes.os)) 73 | }() 74 | 75 | /// Execute parsing based upon passed regular expressions 76 | /// 77 | /// - Parameter rules: rules to validate, the first one which pass validate the set 78 | /// - Returns: return found sets 79 | private func parse(using rules: [Rule]) -> ResultDictionary? { 80 | for rule in rules { 81 | for regex in rule.regexp { 82 | guard let matches = self.agent.matchingStrings(regex: regex) else { continue } 83 | return self.map(results: matches, to: rule.funcs) 84 | } 85 | } 86 | return nil 87 | } 88 | 89 | /// Execute mapping functions for given regula expression into the array of matched strings 90 | /// 91 | /// - Parameters: 92 | /// - results: matched strings array 93 | /// - functions: functions to execute 94 | /// - Returns: parsed data array 95 | private func map(results: [String], to functions: [Funcs]) -> ResultDictionary? { 96 | var data : ResultDictionary = [:] 97 | functions.enumerated().forEach { (idx,function) in 98 | let element: String? = (idx < results.count ? results[idx] : nil) 99 | switch function { 100 | case .r(let key): 101 | if element?.count ?? 0 > 0 { 102 | data[key] = element!.trimmingCharacters(in: .whitespacesAndNewlines) 103 | } 104 | case .rf(let key, let value): 105 | data[key] = value 106 | case .mp(let key, let mapping): 107 | guard let value = element?.uppercased() else { 108 | break 109 | } 110 | for item in mapping.map { 111 | for candidate in item.value { 112 | if value.range(of: candidate, options: .caseInsensitive) != nil { 113 | data[key] = item.key.trimmingCharacters(in: .whitespacesAndNewlines) 114 | break 115 | } 116 | } 117 | if data[key] != nil { break } 118 | } 119 | if data[key] == nil && element?.count ?? 0 > 0 { 120 | data[key] = element! 121 | } 122 | case .rp(let key, let regexp, let replaceWith): 123 | let newValue = element!.replace(withRegex: regexp, with: replaceWith) 124 | if newValue.count > 0 { 125 | data[key] = newValue.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) 126 | } 127 | break 128 | } 129 | } 130 | return (data.count > 0 ? data : nil) 131 | } 132 | } 133 | 134 | // MARK: - Internal Classes 135 | 136 | /// Define a single rule to execute 137 | internal struct Rule { 138 | 139 | /// Set of regular expressions which can validate the rule 140 | public private(set) var regexp: [NSRegularExpression] 141 | 142 | /// Function to execute to parse given regexp results in a valid dictionary 143 | public private(set) var funcs: [Funcs] 144 | 145 | /// Initialize a new rule set 146 | /// 147 | /// - Parameters: 148 | /// - regexp: regular expressions 149 | /// - funcs: function to parse matched regular expression substrings 150 | public init(_ regexp: [String], _ funcs: [Funcs]) { 151 | self.regexp = regexp.map { (regex) in 152 | try! NSRegularExpression(pattern: regex, options: [.caseInsensitive]) 153 | } 154 | 155 | self.funcs = funcs 156 | } 157 | 158 | } 159 | 160 | /// Mapped Dictionary 161 | internal protocol MappedKeys { 162 | var map: [String:[String]] { get } 163 | } 164 | 165 | /// Functions available to parse data 166 | /// 167 | /// - r: assign matched substring to given key 168 | /// - rf: assign fixed value to given key 169 | /// - rp: assign matched substring by sanitizing with another regexp 170 | /// - mp: map value to dictionary and assign to key 171 | internal enum Funcs { 172 | case r(_: Key) 173 | case rf(_: Key, _: String) 174 | case rp(_: Key, _: String, _: String) 175 | case mp(_: Key, _: MappedKeys) 176 | } 177 | 178 | /// Available keys 179 | /// 180 | /// - model: model of the device 181 | /// - name: name (multiple uses) 182 | /// - vendor: vendor of the device 183 | /// - type: type (multiple uses) 184 | /// - version: version (multiple uses) 185 | /// - arch: architecture of the device 186 | public enum Key { 187 | case model 188 | case name 189 | case vendor 190 | case type 191 | case version 192 | case arch 193 | } 194 | 195 | public typealias ResultDictionary = [Key:String] 196 | 197 | // MARK: - Public Represented Objects 198 | 199 | public protocol ParsableData { 200 | init?(_ data: ResultDictionary?) 201 | } 202 | 203 | /// CPU Architecture 204 | public struct CPU: ParsableData { 205 | 206 | /// Architecture identifier 207 | public private(set) var identifier: String? 208 | 209 | public init?(_ data: ResultDictionary?) { 210 | guard let arch = data?[.arch] else { return nil } 211 | self.identifier = arch 212 | } 213 | } 214 | 215 | /// Browser Identifier 216 | public struct Browser: ParsableData { 217 | 218 | /// Browser name 219 | public private(set) var name: String? 220 | 221 | /// Browser version 222 | public private(set) var version: String? 223 | 224 | public init?(_ data: ResultDictionary?) { 225 | guard let data = data else { return nil } 226 | if data[.name] == nil && data[.version] == nil { return nil } 227 | self.name = data[.name] 228 | self.version = data[.version] 229 | } 230 | } 231 | 232 | /// Device Identifier 233 | public struct Device: ParsableData { 234 | 235 | /// Device vendor 236 | public private(set) var vendor: String? 237 | 238 | /// Device type 239 | public private(set) var type: String? 240 | 241 | /// Device model 242 | public private(set) var model: String? 243 | 244 | public init?(_ data: ResultDictionary?) { 245 | guard let data = data else { return nil } 246 | self.vendor = data[.vendor] 247 | self.type = data[.type] 248 | self.model = data[.model] 249 | if self.vendor == nil && self.type == nil && self.model == nil { 250 | return nil 251 | } 252 | } 253 | } 254 | 255 | /// Browser Engine 256 | public struct Engine: ParsableData { 257 | 258 | /// Browser version 259 | public private(set) var version: String? 260 | 261 | /// Browser name 262 | public private(set) var name: String? 263 | 264 | public init?(_ data: ResultDictionary?) { 265 | guard let data = data else { return nil } 266 | self.version = data[.version] 267 | self.name = data[.name] 268 | if self.version == nil && self.name == nil { 269 | return nil 270 | } 271 | } 272 | } 273 | 274 | /// Operating Systems 275 | public struct OS: ParsableData { 276 | 277 | /// Operating system version 278 | public private(set) var version: String? 279 | 280 | /// Operating system name 281 | public private(set) var name: String? 282 | 283 | public init?(_ data: ResultDictionary?) { 284 | guard let data = data else { return nil } 285 | self.version = data[.version] 286 | self.name = data[.name] 287 | if self.version == nil && self.name == nil { 288 | return nil 289 | } 290 | } 291 | } 292 | 293 | // MARK: All Regular Expressions 294 | 295 | internal struct Regexes { 296 | 297 | /// Browsers 298 | static let browsers: [Rule] = [ 299 | Rule([ 300 | "(opera\\smini)\\/([\\w\\.-]+)", // Opera Mini 301 | "(opera\\s[mobiletab]+).+version\\/([\\w\\.-]+)", // Opera Mobi/Tablet 302 | "(opera).+version\\/([\\w\\.]+)", // Opera > 9.80 303 | "(opera)[\\/\\s]+([\\w\\.]+)" // Opera < 9.80 304 | ],[.r(.name),.r(.version)]), 305 | Rule([ 306 | "(opios)[\\/\\s]+([\\w\\.]+)", // Opera mini on iphone >= 8.0 307 | ], [.rf(.name,"Opera Mini"), .r(.version)]), 308 | Rule([ 309 | "\\s(opr)\\/([\\w\\.]+)", // Opera Webkit 310 | ], [.rf(.name,"Opera"),.r(.version)]), 311 | Rule([ 312 | // Mixed 313 | "(kindle)\\/([\\w\\.]+)", // Kindle 314 | "(lunascape|maxthon|netfront|jasmine|blazer)[\\/\\s]?([\\w\\.]+)*", // Lunascape/Maxthon/Netfront/Jasmine/Blazer 315 | // Trident based 316 | "(avant\\s|iemobile|slim|baidu)(?:browser)?[\\/\\s]?([\\w\\.]*)", // Avant/IEMobile/SlimBrowser/Baidu 317 | "(?:ms|\\()(ie)\\s([\\w\\.]+)", // Internet Explorer 318 | // Webkit/KHTML based 319 | "(rekonq)\\/([\\w\\.]+)*", // Rekonq 320 | "(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser)\\/([\\w\\.-]+)" // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser 321 | ], [.r(.name),.r(.version)]), 322 | Rule([ 323 | "(trident).+rv[:\\s]([\\w\\.]+).+like\\sgecko", // IE11 324 | ], [.rf(.name,"IE"),.r(.version)]), 325 | Rule([ 326 | "(edge)\\/((\\d+)?[\\w\\.]+)", // Microsoft Edge 327 | ], [.r(.name),.r(.version)]), 328 | Rule([ 329 | "(yabrowser)\\/([\\w\\.]+)", // Yandex 330 | ], [.rf(.name,"Yandex"),.r(.version)]), 331 | Rule([ 332 | "(puffin)\\/([\\w\\.]+)", // Puffin 333 | ], [.rf(.name,"Puffin"),.r(.version)]), 334 | Rule([ 335 | "((?:[\\s\\/])uc?\\s?browser|(?:juc.+)ucweb)[\\/\\s]?([\\w\\.]+)" // UCBrowser 336 | ], [.rf(.name,"UCBrowser"),.r(.version)]), 337 | Rule([ 338 | "(comodo_dragon)\\/([\\w\\.]+)", // Comodo Dragon 339 | ], [.rp(.name,"_", " "), .r(.version)]), 340 | Rule([ 341 | "(micromessenger)\\/([\\w\\.]+)", // WeChat 342 | ], [.rf(.name,"WeChat"),.r(.version)]), 343 | Rule([ 344 | "(QQ)\\/([\\d\\.]+)", // QQ, aka ShouQ 345 | ], [.r(.name),.r(.version)]), 346 | Rule([ 347 | "m?(qqbrowser)[\\/\\s]?([\\w\\.]+)", // QQBrowser 348 | ], [.r(.name),.r(.version)]), 349 | Rule([ 350 | "xiaomi\\/miuibrowser\\/([\\w\\.]+)", // MIUI Browser 351 | ], [.r(.version), .rf(.name,"MIUI Browser")]), 352 | Rule([ 353 | ";fbav\\/([\\w\\.]+);", // Facebook App for iOS & Android 354 | ], [.r(.version), .rf(.name,"Facebook")]), 355 | Rule([ 356 | "headlesschrome(?:\\/([\\w\\.]+)|\\s)", // Chrome Headless 357 | ], [.r(.version),.rf(.name,"Chrome Headless")]), 358 | Rule([ 359 | "\\swv\\).+(chrome)\\/([\\w\\.]+)", // Chrome WebView 360 | ], [.rp(.name,"(.+)/","$1 WebView"),.r(.version)]), 361 | Rule([ 362 | "((?:oculus|samsung)browser)\\/([\\w\\.]+)" // Oculus / Samsung Browser 363 | ], [.rp(.name,"(.+(?:g|us))(.+)/","$1 $2"),.r(.version)]), 364 | Rule([ 365 | "android.+version\\/([\\w\\.]+)\\s+(?:mobile\\s?safari|safari)*", // Android Browser 366 | ],[.r(.version),.rf(.name,"Android Browser")]), 367 | Rule([ 368 | "(chrome|omniweb|arora|[tizenoka]{5}\\s?browser)\\/v?([\\w\\.]+)", // Chrome/OmniWeb/Arora/Tizen/Nokia 369 | ],[.r(.name),.r(.version)]), 370 | Rule([ 371 | "(dolfin)\\/([\\w\\.]+)", // Dolphin 372 | ], [.rf(.name,"Dolphin"),.r(.version)]), 373 | Rule([ 374 | "((?:android.+)crmo|crios)\\/([\\w\\.]+)", // Chrome for Android/iOS 375 | ],[.rf(.name,"Chrome"),.r(.version)]), 376 | Rule([ 377 | "(coast)\\/([\\w\\.]+)", // Opera Coast 378 | ],[.rf(.name,"Opera Coast"),.r(.version)]), 379 | Rule([ 380 | "fxios\\/([\\w\\.-]+)", // Firefox for iOS 381 | ], [.r(.version),.rf(.name,"Firefox")]), 382 | Rule([ 383 | "version\\/([\\w\\.]+).+?mobile\\/\\w+\\s(safari)", // Mobile Safari 384 | ], [.r(.version),.rf(.name,"Mobile Safari")]), 385 | Rule([ 386 | "version\\/([\\w\\.]+).+?(mobile\\s?safari|safari)", // Safari & Safari Mobile 387 | ], [.r(.version),.r(.name)]), 388 | Rule([ 389 | "webkit.+?(gsa)\\/([\\w\\.]+).+?(mobile\\s?safari|safari)(\\/[\\w\\.]+)", // Google Search Appliance on iOS 390 | ], [.rf(.name,"GSA"),.r(.version)]), 391 | Rule([ 392 | "webkit.+?(mobile\\s?safari|safari)(\\/[\\w\\.]+)", // Safari < 3.0 393 | ], [.r(.name),.mp(.version, OldSafariMap())]), 394 | Rule([ 395 | "(konqueror)\\/([\\w\\.]+)/i,", // Konqueror 396 | "(webkit|khtml)\\/([\\w\\.]+)", 397 | ],[.r(.name),.r(.version)]), 398 | Rule([ 399 | // Gecko based 400 | "(navigator|netscape)\\/([\\w\\.-]+)", // Netscape 401 | ],[.rf(.name,"Netscape"),.r(.version)]), 402 | Rule([ 403 | "(swiftfox)", // Swiftfox 404 | "(icedragon|iceweasel|camino|chimera|fennec|maemo\\sbrowser|minimo|conkeror)[\\/\\s]?([\\w\\.\\+]+)", // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror 405 | "(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\\/([\\w\\.-]+)", // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix 406 | "(mozilla)\\/([\\w\\.]+).+rv\\:.+gecko\\/\\d+", // Mozilla 407 | // Other 408 | "(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir)[\\/\\s]?([\\w\\.]+)", // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir 409 | "(links)\\s\\(([\\w\\.]+)", // Links, 410 | "(gobrowser)\\/?([\\w\\.]+)*", // GoBrowser 411 | "(ice\\s?browser)\\/v?([\\w\\._]+)", // ICE Browser 412 | "(mosaic)[\\/\\s]([\\w\\.]+)", // Mosaic 413 | ], [.r(.name),.r(.version)]) 414 | ] 415 | 416 | /// CPU Architectures 417 | static let cpu: [Rule] = [ 418 | Rule([ 419 | "(?:(amd|x(?:(?:86|64)[_-])?|wow|win)64)[;\\)]", // AMD64 420 | ], [.rf(.arch,"amd64")]), 421 | Rule([ 422 | "(ia32(?=;))" // IA32 (quicktime) 423 | ], [.r(.arch)]), 424 | Rule([ 425 | "((?:i[346]|x)86)[;\\)]" // // IA32 426 | ],[.rf(.arch,"ia32")]), 427 | Rule([ 428 | "windows\\s(ce|mobile);\\sppc;", // PocketPC mistakenly identified as PowerPC 429 | ],[.rf(.arch,"arm")]), 430 | Rule([ 431 | "((?:ppc|powerpc)(?:64)?)(?:\\smac|;|\\))", // PowerPC 432 | ],[.rp(.arch,"ower","")]), 433 | Rule([ 434 | "(sun4\\w)[;\\)]", // SPARC 435 | ],[.rf(.arch,"sparc")]), 436 | Rule([ 437 | "((?:avr32|ia64(?=;))|68k(?=\\))|arm(?:64|(?=v\\d+;))|(?=atmel\\s)avr|(?:irix|mips|sparc)(?:64)?(?=;)|pa-risc)", // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC 438 | ],[.r(.arch)]) 439 | ] 440 | 441 | /// Devices 442 | static let device: [Rule] = [ 443 | Rule([ 444 | "\\((ipad|playbook);[\\w\\s\\);-]+(rim|apple)", // iPad/PlayBook 445 | ],[.r(.model),.r(.vendor),.rf(.type,"tablet")]), 446 | Rule([ 447 | "applecoremedia\\/[\\w\\.]+ \\((ipad)/", // iPad 448 | ],[.r(.model),.rf(.vendor,"apple"),.rf(.type,"tablet")]), 449 | Rule([ 450 | "(apple\\s{0,1}tv)", // Apple TV 451 | ],[.rf(.model,"apple tv"),.rf(.vendor,"apple")]), 452 | Rule([ 453 | "(archos)\\s(gamepad2?)", // Archos 454 | "(hp).+(touchpad)", // HP TouchPad 455 | "(hp).+(tablet)", // HP Tablet 456 | "(kindle)\\/([\\w\\.]+)", // Kindle 457 | "\\s(nook)[\\w\\s]+build\\/(\\w+)", // Nook 458 | "(dell)\\s(strea[kpr\\s\\d]*[\\dko])", // Dell Streak 459 | ],[.r(.vendor),.r(.model),.rf(.type,"tablet")]), 460 | Rule([ 461 | "(kf[A-z]+)\\sbuild\\/[\\w\\.]+.*silk\\/", // Kindle Fire HD 462 | ],[.r(.model),.rf(.vendor,"amazon"),.rf(.type,"tablet")]), 463 | Rule([ 464 | "(sd|kf)[0349hijorstuw]+\\sbuild\\/[\\w\\.]+.*silk\\/", // Fire Phone 465 | ],[.mp(.model,AmazonDeviceMap()),.rf(.vendor,"amazon"),.rf(.type,"mobile")]), 466 | Rule([ 467 | "\\((ip[honed|\\s\\w*]+);.+(apple)", // iPod/iPhone 468 | ],[.r(.model),.r(.vendor),.rf(.type,"mobile")]), 469 | Rule([ 470 | "\\((ip[honed|\\s\\w*]+);", // iPod/iPhone 471 | ],[.r(.model),.rf(.vendor,"apple"),.rf(.type,"mobile")]), 472 | Rule([ 473 | "(blackberry)[\\s-]?(\\w+)", // BlackBerry 474 | "(blackberry|benq|palm(?=\\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[\\s_-]?([\\w-]+)*", // BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron 475 | "(hp)\\s([\\w\\s]+\\w)", // HP iPAQ 476 | "(asus)-?(\\w+)", // Asus 477 | ],[.r(.vendor),.r(.model),.rf(.type,"mobile")]), 478 | Rule([ 479 | "\\(bb10;\\s(\\w+)", // BlackBerry 10 480 | ],[.r(.model),.rf(.vendor,"BlackBerry"),.rf(.type,"mobile")]), 481 | Rule([ 482 | "android.+(transfo[prime\\s]{4,10}\\s\\w+|eeepc|slider\\s\\w+|nexus 7|padfone)", // Asus Tablets 483 | ],[.r(.model),.rf(.vendor,"asus"),.rf(.type,"tablet")]), 484 | Rule([ 485 | "(sony)\\s(tablet\\s[ps])\\sbuild\\/", // Sony Xperia 486 | "(sony)?(?:sgp.+)\\sbuild\\/" 487 | ], [.rf(.vendor,"sony"),.rf(.model,"xperia tablet"),.rf(.type,"tablet")]), 488 | Rule([ 489 | "android.+\\s([c-g]\\d{4}|so[-l]\\w+)\\sbuild\\/" // Sony 490 | ],[.r(.model),.rf(.vendor,"sony"),.rf(.type,"mobile")]), 491 | Rule([ 492 | "\\s(ouya)\\s", // Ouya 493 | "(nintendo)\\s([wids3u]+)", // Nintendo 494 | ],[.r(.vendor),.r(.model),.rf(.type,"console")]), 495 | Rule([ 496 | "android.+;\\s(shield)\\sbuild", // Nvidia 497 | ], [.r(.model),.rf(.vendor,"sony"),.rf(.type,"console")]), 498 | Rule([ 499 | "(playstation\\s[34portablevi]+)", // Playstation 500 | ],[.r(.model),.rf(.vendor,"sony"),.rf(.type,"console")]), 501 | Rule([ 502 | "(sprint\\s(\\w+))", // Sprint Phones 503 | ],[.mp(.vendor,SprintVendorMap()), .mp(.model, SprintModelMap()), .rf(.type,"mobile")]), 504 | Rule([ 505 | "(lenovo)\\s?(S(?:5000|6000)+(?:[-][\\w+]))", // Lenovo tablets 506 | ], [.r(.vendor),.r(.model),.rf(.type,"tablet")]), 507 | Rule([ 508 | "(htc)[;_\\s-]+([\\w\\s]+(?=\\))|\\w+)*", // HTC 509 | "(zte)-(\\w+)*", // ZTE, 510 | "(alcatel|geeksphone|lenovo|nexian|panasonic|(?=;\\s)sony)[_\\s-]?([\\w-]+)*", // Alcatel/GeeksPhone/Lenovo/Nexian/Panasonic/Sony 511 | ], [.r(.vendor),.rp(.model,"_"," "),.rf(.type,"mobile")]), 512 | Rule([ 513 | "(nexus\\s9)", // HTC Nexus 9 514 | ], [.r(.model),.rf(.vendor,"htc"),.rf(.type,"tablet")]), 515 | Rule([ 516 | "d\\/huawei([\\w\\s-]+)[;\\)]", // Huawei 517 | "(nexus\\s6p)" 518 | ],[.r(.model),.rf(.vendor,"huawei"),.rf(.type,"mobile")]), 519 | Rule([ 520 | "(microsoft);\\s(lumia[\\s\\w]+)", // Microsoft Lumia 521 | ],[.r(.vendor),.r(.model),.rf(.type,"mobile")]), 522 | Rule([ 523 | "[\\s\\(;](xbox(?:\\sone)?)[\\s\\);]", // Microsoft Xbox 524 | ],[.r(.model),.rf(.vendor,"microsoft"),.rf(.type,"console")]), 525 | Rule([ 526 | "(kin\\.[onetw]{3})", // Microsoft Kin 527 | ],[.rp(.model,"\\."," "),.rf(.vendor,"microsoft"),.rf(.type,"mobile")]), 528 | Rule([ 529 | "\\s(milestone|droid(?:[2-4x]|\\s(?:bionic|x2|pro|razr))?(:?\\s4g)?)[\\w\\s]+build\\/", // Motorola 530 | "mot[\\s-]?(\\w+)*", 531 | "(XT\\d{3,4}) build\\/", 532 | "(nexus\\s6)" 533 | ],[.r(.model),.rf(.vendor,"motorola"),.rf(.type,"mobile")]), 534 | Rule([ 535 | "android.+\\s(mz60\\d|xoom[\\s2]{0,2})\\sbuild\\/", // Motorola 536 | ],[.r(.model),.rf(.vendor,"motorola"),.rf(.type,"tablet")]), 537 | Rule([ 538 | "hbbtv\\/\\d+\\.\\d+\\.\\d+\\s+\\([\\w\\s]*;\\s*(\\w[^;]*);([^;]*)", // HbbTV devices 539 | ],[.r(.vendor),.r(.model),.rf(.type,"smarttv")]), 540 | Rule([ 541 | "hbbtv.+maple;(\\d+)", 542 | ],[.rp(.model,"^/","SmartTV"),.rf(.vendor,"samsung"),.rf(.type,"smarttv")]), 543 | Rule([ 544 | "\\(dtv[\\);].+(aquos)", // Sharp 545 | ],[.r(.model),.rf(.vendor,"sharp"),.rf(.type,"smarttv")]), 546 | Rule([ 547 | "android.+((sch-i[89]0\\d|shw-m380s|gt-p\\d{4}|gt-n\\d+|sgh-t8[56]9|nexus 10))", // Samsung 548 | "((SM-T\\w+))" 549 | ],[.rf(.vendor,"samsung"),.r(.model),.rf(.type,"tablet")]), 550 | Rule([ 551 | "smart-tv.+(samsung)", 552 | ],[.r(.vendor),.rf(.type,"smarttv"),.r(.model)]), 553 | Rule([ 554 | "((s[cgp]h-\\w+|gt-\\w+|galaxy\\snexus|sm-\\w[\\w\\d]+))", 555 | "(sam[sung]*)[\\s-]*(\\w+-?[\\w-]*)*", 556 | "sec-((sgh\\w+))" 557 | ],[.rf(.vendor,"samsung"),.r(.model),.rf(.type,"mobile")]), 558 | Rule([ 559 | "sie-(\\w+)*", // Siemens 560 | ],[.r(.model),.rf(.vendor,"siemes"),.rf(.type,"mobile")]), 561 | Rule([ 562 | "(maemo|nokia).*(n900|lumia\\s\\d+)", // Nokia 563 | "(nokia)[\\s_-]?([\\w-]+)*", 564 | ],[.rf(.vendor,"nokia"),.r(.model),.rf(.type,"mobile")]), 565 | Rule([ 566 | "android\\s3\\.[\\s\\w;-]{10}(a\\d{3})", // Acer 567 | ],[.r(.model),.rf(.vendor,"acer"),.rf(.type,"tablet")]), 568 | Rule([ 569 | "android.+([vl]k\\-?\\d{3})\\s+build", // LG Tablet 570 | ],[.r(.model),.rf(.vendor,"lg"),.rf(.type,"tablet")]), 571 | Rule([ 572 | "android\\s3\\.[\\s\\w;-]{10}(lg?)-([06cv9]{3,4})", // LG Tablet 573 | ],[.rf(.vendor,"lg"),.r(.model),.rf(.type,"tablet")]), 574 | Rule([ 575 | "(lg) netcast\\.tv", // LG SmartTV 576 | ],[.r(.vendor),.r(.model),.rf(.type,"smarttv")]), 577 | Rule([ 578 | "(nexus\\s[45])", // LG 579 | "lg[e;\\s\\/-]+(\\w+)*", 580 | "android.+lg(\\-?[\\d\\w]+)\\s+build", 581 | ],[.r(.model),.rf(.vendor,"lg"),.rf(.type,"mobile")]), 582 | Rule([ 583 | "android.+(ideatab[a-z0-9\\-\\s]+)", // Lenovo 584 | ],[.r(.model),.rf(.vendor,"lenovo"),.rf(.type,"tablet")]), 585 | Rule([ 586 | "linux;.+((jolla));", // Jolla 587 | ],[.r(.vendor),.r(.model),.rf(.type,"tablet")]), 588 | Rule([ 589 | "((pebble))app\\/[\\d\\.]+\\s", // Pebble 590 | ],[.r(.vendor),.r(.model),.rf(.type,"wearable")]), 591 | Rule([ 592 | "android.+;\\s(oppo)\\s?([\\w\\s]+)\\sbuild", // OPPO 593 | ],[.r(.vendor),.r(.model),.rf(.type,"mobile")]), 594 | Rule([ 595 | "crkey", // Google Chromecast 596 | ],[.rf(.model,"chromecast"),.rf(.vendor,"google")]), 597 | Rule([ 598 | "android.+;\\s(glass)\\s\\d", // Google Glass 599 | ],[.r(.model),.rf(.vendor,"google"),.rf(.type,"wearable")]), 600 | Rule([ 601 | "android.+;\\s(pixel c)\\s", // Google Pixel C 602 | ],[.r(.model),.rf(.vendor,"google"),.rf(.type,"tablet")]), 603 | Rule([ 604 | "android.+;\\s(pixel xl|pixel)\\s", // Google Pixel 605 | ],[.r(.model),.rf(.vendor,"google"),.rf(.type,"mobile")]), 606 | Rule([ 607 | "android.+(\\w+)\\s+build\\/hm\\1", // Xiaomi Hongmi 'numeric' models 608 | "android.+(hm[\\s\\-_]*note?[\\s_]*(?:\\d\\w)?)\\s+build", // Xiaomi Hongmi 609 | "android.+(mi[\\s\\-_]*(?:one|one[\\s_]plus|note lte)?[\\s_]*(?:\\d\\w)?)\\s+build", // Xiaomi Mi 610 | "android.+(redmi[\\s\\-_]*(?:note)?(?:[\\s_]*[\\w\\s]+)?)\\s+build", // Redmi Phones 611 | ],[.rp(.model,"_"," "), .rf(.vendor,"xiaomi"),.rf(.type,"mobile")]), 612 | Rule([ 613 | "android.+(mi[\\s\\-_]*(?:pad)?(?:[\\s_]*[\\w\\s]+)?)\\s+build" // Mi Pad tablets 614 | ],[.rp(.model,"_"," "), .rf(.vendor,"xiaomi"),.rf(.type,"tablet")]), 615 | Rule([ 616 | "android.+;\\s(m[1-5]\\snote)\\sbuild", // Meizu Tablet 617 | ],[.r(.model),.rf(.vendor,"meizu"),.rf(.type,"tablet")]), 618 | Rule([ 619 | "android.+a000(1)\\s+build", // OnePlus 620 | ],[.r(.model),.rf(.vendor,"oneplus"),.rf(.type,"mobile")]), 621 | Rule([ 622 | "android.+[;\\/]\\s*(RCT[\\d\\w]+)\\s+build", // RCA Tablets 623 | ],[.r(.model),.rf(.vendor,"rca"),.rf(.type,"tablet")]), 624 | Rule([ 625 | "android.+[;\\/]\\s*(Venue[\\d\\s]*)\\s+build" // // Dell Venue Tablets 626 | ],[.r(.model),.rf(.vendor,"dell"),.rf(.type,"tablet")]), 627 | Rule([ 628 | "android.+[;\\/]\\s*(Q[T|M][\\d\\w]+)\\s+build", // Verizon Tablet 629 | ],[.r(.model),.rf(.vendor,"verizon"),.rf(.type,"tablet")]), 630 | Rule([ 631 | "android.+[;\\/]\\s+(Barnes[&\\s]+Noble\\s+|BN[RT])(V?.*)\\s+build", // Barnes & Noble Tablet 632 | ],[.rf(.vendor,"barnes & noble"), .r(.model),.rf(.type,"tablet")]), 633 | Rule([ 634 | "android.+[;\\/]\\s+(TM\\d{3}.*\\b)\\s+build", // Barnes & Noble Tablet 635 | ],[.r(.model),.rf(.vendor,"nuvision"),.rf(.type,"tablet")]), 636 | Rule([ 637 | "android.+[;\\/]\\s*(zte)?.+(k\\d{2})\\s+build", // ZTE K Series Tablet 638 | ],[.rf(.vendor,"zte"),.r(.model),.rf(.type,"tablet")]), 639 | Rule([ 640 | "android.+[;\\/]\\s*(gen\\d{3})\\s+build.*49h", // Swiss GEN Mobile 641 | ],[.r(.model),.rf(.vendor,"swiss"),.rf(.type,"mobile")]), 642 | Rule([ 643 | "android.+[;\\/]\\s*(zur\\d{3})\\s+build", // Swiss ZUR Tablet 644 | ],[.r(.model),.rf(.vendor,"swiss"),.rf(.type,"tablet")]), 645 | Rule([ 646 | "android.+[;\\/]\\s*((Zeki)?TB.*\\b)\\s+build", // Zeki Tablets 647 | ],[.r(.model),.rf(.vendor,"zeki"),.rf(.type,"tablet")]), 648 | Rule([ 649 | "(android).+[;\\/]\\s+([YR]\\d{2}x?.*)\\s+build", // Dragon Touch Tablet 650 | "android.+[;\\/]\\s+(Dragon[\\-\\s]+Touch\\s+|DT)(.+)\\s+build", 651 | ],[.rf(.vendor,"dragon touch"),.r(.model),.rf(.type,"tablet")]), 652 | Rule([ 653 | "android.+[;\\/]\\s*(NS-?.+)\\s+build", // Insignia Tablets 654 | ],[.r(.model),.rf(.vendor,"insignia"),.rf(.type,"tablet")]), 655 | Rule([ 656 | "android.+[;\\/]\\s*((NX|Next)-?.+)\\s+build", // NextBook Tablets 657 | ],[.r(.model),.rf(.vendor,"nextbook"),.rf(.type,"tablet")]), 658 | Rule([ 659 | "android.+[;\\/]\\s*(Xtreme\\_?)?(V(1[045]|2[015]|30|40|60|7[05]|90))\\s+build", // Voice Xtreme Phones 660 | ],[.rf(.vendor,"voice"),.r(.model),.rf(.type,"mobile")]), 661 | Rule([ 662 | "android.+[;\\/]\\s*(LVTEL\\-?)?(V1[12])\\s+build", // LvTel Phones 663 | ],[.rf(.vendor,"lvtel"),.r(.model),.rf(.type,"mobile")]), 664 | Rule([ 665 | "android.+[;\\/]\\s*(V(100MD|700NA|7011|917G).*\\b)\\s+build" // Envizen Tablets 666 | ],[.r(.model),.rf(.vendor,"envizen"),.rf(.type,"tablet")]), 667 | Rule([ 668 | "android.+[;\\/]\\s*(Le[\\s\\-]+Pan)[\\s\\-]+(.*\\b)\\s+build", // Le Pan Tablets 669 | ],[.r(.vendor),.r(.model),.rf(.type,"tablet")]), 670 | Rule([ 671 | "android.+[;\\/]\\s*(Trio[\\s\\-]*.*)\\s+build", // MachSpeed Tablets 672 | ],[.r(.model),.rf(.vendor,"machspeed"),.rf(.type,"tablet")]), 673 | Rule([ 674 | "android.+[;\\/]\\s*(Trinity)[\\-\\s]*(T\\d{3})\\s+build", // Trinity Tablets 675 | ],[.r(.vendor),.r(.model),.rf(.type,"tablet")]), 676 | Rule([ 677 | "android.+[;\\/]\\s*TU_(1491)\\s+build", // Rotor Tablets 678 | ],[.r(.model),.rf(.vendor,"rotor"),.rf(.type,"tablet")]), 679 | Rule([ 680 | "android.+(KS(.+))\\s+build", // Amazon Kindle Tablets 681 | ],[.r(.model),.rf(.vendor,"amazon"),.rf(.type,"tablet")]), 682 | Rule([ 683 | "android.+(Gigaset)[\\s\\-]+(Q.+)\\s+build/i]", // Gigaset Tablets 684 | ],[.r(.vendor),.r(.model),.rf(.type,"tablet")]), 685 | Rule([ 686 | "\\s(tablet|tab)[;\\/]", // Unidentifiable Tablet 687 | "\\s(mobile)(?:[;\\/]|\\ssafari)", // Unidentifiable Mobile 688 | ],[.r(.type),.r(.vendor),.r(.model)]), 689 | Rule([ 690 | "(android.+)[;\\/].+build", // Generic Android Device 691 | ],[.r(.model),.rf(.vendor,"generic")]) 692 | ] 693 | 694 | /// Browser Engines 695 | static let engine: [Rule] = [ 696 | Rule([ 697 | "windows.+\\sedge\\/([\\w\\.]+)", // EdgeHTML 698 | ],[.r(.version),.rf(.name,"EdgeHTML")]), 699 | Rule([ 700 | "(presto)\\/([\\w\\.]+)", // Presto 701 | "(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\\/([\\w\\.]+)", // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m 702 | "(khtml|tasman|links)[\\/\\s]\\(?([\\w\\.]+)", // KHTML/Tasman/Links 703 | "(icab)[\\/\\s]([23]\\.[\\d\\.]+)" // iCab 704 | ],[.r(.name),.r(.version)]), 705 | Rule([ 706 | "rv\\:([\\w\\.]+).*(gecko)" // Gecko 707 | ],[.r(.version),.r(.name)]), 708 | ] 709 | 710 | /// Operating Systems 711 | static let os: [Rule] = [ 712 | Rule([ 713 | // Windows based 714 | "microsoft\\s(windows)\\s(vista|xp)", // Windows (iTunes) 715 | ],[.r(.name),.r(.version)]), 716 | Rule([ 717 | "(windows)\\snt\\s6\\.2;\\s(arm)", // Windows RT 718 | "(windows\\sphone(?:\\sos)*)[\\s\\/]?([\\d\\.\\s]+\\w)*", // Windows Phone 719 | "(windows\\smobile|windows)[\\s\\/]?([ntce\\d\\.\\s]+\\w)" 720 | ],[.r(.name),.mp(.version,WindowsOSMap())]), 721 | Rule([ 722 | "(win(?=3|9|n)|win\\s9x\\s)([nt\\d\\.]+)", // Windows 723 | ],[.rf(.name,"windows"),.mp(.version,WindowsOSMap())]), 724 | Rule([ 725 | // Mobile/Embedded OS 726 | "\\((bb)(10);" // BlackBerry 10 727 | ],[.rf(.name,"blackberry"),.r(.version)]), 728 | Rule([ 729 | "(blackberry)\\w*\\/?([\\w\\.]+)*", // Blackberry 730 | "(tizen)[\\/\\s]([\\w\\.]+)", // Tizen 731 | "(android|webos|palm\\sos|qnx|bada|rim\\stablet\\sos|meego|contiki)[\\/\\s-]?([\\w\\.]+)*", // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki 732 | "linux;.+(sailfish);" // Sailfish OS 733 | ],[.r(.name),.r(.version)]), 734 | Rule([ 735 | "(symbian\\s?os|symbos|s60(?=;))[\\/\\s-]?([\\w\\.]+)*", // Symbian 736 | ],[.rf(.name,"symbian"),.r(.version)]), 737 | Rule([ 738 | "\\((series40);", // Series 40 739 | ],[.r(.name)]), 740 | Rule([ 741 | "mozilla.+\\(mobile;.+gecko.+firefox", // Firefox OS 742 | ],[.rf(.name,"firefox os"),.r(.version)]), 743 | Rule([ 744 | // Console 745 | "(nintendo|playstation)\\s([wids34portablevu]+)", // Nintendo/Playstation 746 | // GNU/Linux based 747 | "(mint)[\\/\\s\\(]?(\\w+)*", // Mint 748 | "(mageia|vectorlinux)[;\\s]", // Mageia/VectorLinux 749 | // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware 750 | // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus 751 | "(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|(?=\\s)arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\\/\\s-]?(?!chrom)([\\w\\.-]+)*", 752 | // Hurd/Linux 753 | "(hurd|linux)\\s?([\\w\\.]+)*", // Hurd/Linux 754 | "(gnu)\\s?([\\w\\.]+)*" // GNU 755 | ],[.r(.name),.r(.version)]), 756 | Rule([ 757 | "(cros)\\s[\\w]+\\s([\\w\\.]+\\w)", // Chromium OS 758 | ],[.rf(.name,"chromium os"),.r(.version)]), 759 | Rule([ 760 | "(sunos)\\s?([\\w\\.]+\\d)*", // Solaris 761 | ],[.rf(.name,"solaris"),.r(.version)]), 762 | Rule([ 763 | // BSD based 764 | "\\s([frentopc-]{0,4}bsd|dragonfly)\\s?([\\w\\.]+)*", // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly 765 | ],[.r(.name),.r(.version)]), 766 | Rule([ 767 | "(haiku)\\s(\\w+)", // Haiku 768 | ],[.r(.name),.r(.version)]), 769 | Rule([ 770 | "cfnetwork\\/.+darwin", 771 | "ip[honead]+(?:.*os\\s([\\w]+)\\slike\\smac|;\\sopera)", // iOS 772 | ],[.rp(.version,"_", "."),.rf(.name,"ios")]), 773 | Rule([ 774 | "(mac\\sos\\sx)\\s?([\\w\\s\\.]+\\w)*", 775 | "(macintosh|mac(?=_powerpc)\\s)" // Mac OS 776 | ],[.rf(.name,"mac os"),.rp(.version,"_",".")]), 777 | Rule([ 778 | // Other 779 | "((?:open)?solaris)[\\/\\s-]?([\\w\\.]+)*", // Solaris 780 | "(aix)\\s((\\d)(?=\\.|\\)|\\s)[\\w\\.]*)*", // AIX 781 | "(plan\\s9|minix|beos|os\\/2|amigaos|morphos|risc\\sos|openvms)", // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS 782 | "(unix)\\s?([\\w\\.]+)*" // UNIX 783 | ],[.r(.name),.r(.version)]) 784 | ] 785 | 786 | } 787 | 788 | // MARK: - Special Mapping Data 789 | 790 | internal struct OldSafariMap: MappedKeys { 791 | public var map: [String:[String]] = [:] 792 | 793 | init() { 794 | self.map = [ 795 | "1.0" : ["/8"], 796 | "1.2" : ["/1"], 797 | "1.3" : ["/3"], 798 | "2.0" : ["/412"], 799 | "2.0.2" : ["/416"], 800 | "2.0.3" : ["/417"], 801 | "2.0.4" : ["/419"], 802 | "?" : ["/"] 803 | ] 804 | } 805 | } 806 | 807 | internal struct AmazonDeviceMap: MappedKeys { 808 | public var map: [String:[String]] = [:] 809 | 810 | init() { 811 | self.map = [ 812 | "Fire Phone" : ["SD", "KF"] 813 | ] 814 | } 815 | } 816 | 817 | internal struct SprintVendorMap: MappedKeys { 818 | public var map: [String:[String]] = [:] 819 | 820 | init() { 821 | self.map = [ 822 | "HTC" : ["APA"], 823 | "Sprint" : ["Sprint"] 824 | ] 825 | } 826 | } 827 | 828 | internal struct SprintModelMap: MappedKeys { 829 | public var map: [String:[String]] = [:] 830 | 831 | init() { 832 | self.map = [ 833 | "Evo Shift 4G" : ["7373KT"] 834 | ] 835 | } 836 | } 837 | 838 | internal struct WindowsOSMap: MappedKeys { 839 | public var map: [String:[String]] = [:] 840 | 841 | init() { 842 | self.map = [ 843 | "ME" : ["4.90"], 844 | "NT 3.11" : ["NT3.51"], 845 | "NT 4.0" : ["NT4.0"], 846 | "2000" : ["NT 5.0"], 847 | "XP" : ["NT 5.1", "NT 5.2"], 848 | "Vista" : ["NT 6.0"], 849 | "7" : ["NT 6.1"], 850 | "8" : ["NT 6.2"], 851 | "8.1" : ["NT 6.3"], 852 | "10" : ["NT 6.4", "NT 10.0"], 853 | "RT" : ["ARM"] 854 | ] 855 | } 856 | } 857 | 858 | 859 | // MARK: - String Regex Extension 860 | 861 | public extension String { 862 | 863 | /// Return all matched groups extracted from self string using passed regexp 864 | /// 865 | /// - Parameter regex: regular express used to filter 866 | /// - Returns: matching strings 867 | func matchingStrings(regex: NSRegularExpression) -> [String]? { 868 | let nsString = NSString(string: self) 869 | let results = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length)) 870 | let matches = results.map { result in 871 | (0.. 1 ? Array(first_group[1...]) : first_group 879 | } 880 | 881 | /// Replace string matching given regex with passed string 882 | /// 883 | /// - Parameters: 884 | /// - pattern: regular expression 885 | /// - replaceWith: replacing value 886 | /// - Returns: new string; if error occurs the same input string is returned 887 | func replace(withRegex pattern: String, with replaceWith: String = "") -> String { 888 | do { 889 | let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive]) 890 | let range = NSMakeRange(0, self.count) 891 | return regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: replaceWith) 892 | } catch { 893 | return self 894 | } 895 | } 896 | } 897 | -------------------------------------------------------------------------------- /TestApplication/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TestApplication 4 | // 5 | // Created by danielemargutti on 01/11/2017. 6 | // Copyright © 2017 UAParserSwift. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /TestApplication/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /TestApplication/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /TestApplication/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /TestApplication/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TestApplication/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TestApplication 4 | // 5 | // Created by danielemargutti on 01/11/2017. 6 | // Copyright © 2017 UAParserSwift. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import UAParserSwift 11 | 12 | class ViewController: UIViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | 22 | _ = UAParser(agent: "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7") 23 | } 24 | 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Tests/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malcommac/UAParserSwift/a8057c7cff60db2cdf31d0a0a68ce430754ab64e/Tests/.DS_Store -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import UAParserSwiftTests 3 | 4 | XCTMain([ 5 | testCase(UAParserSwiftTests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /Tests/UAParserSwiftTests/UAParserSwift_Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UAParserSwiftTests.swift 3 | // UAParserSwift 4 | // 5 | // Created by Daniele Margutti on 01/11/2017. 6 | // Copyright © 2017 UAParserSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | import UAParserSwift 12 | 13 | public struct TestItem: Decodable { 14 | public var desc: String 15 | public var ua: String 16 | public var expect: [String: String] 17 | } 18 | 19 | class UAParserSwiftTests: XCTestCase { 20 | 21 | func loadFile(named: String) -> [TestItem]? { 22 | guard let filePath = Bundle(for: UAParserSwiftTests.self).path(forResource: named, ofType: "json") else { 23 | return nil 24 | } 25 | do { 26 | let jsonData = try Data(contentsOf: URL(fileURLWithPath: filePath)) 27 | let decoder = JSONDecoder() 28 | let data = try decoder.decode([TestItem].self, from: jsonData) 29 | return data 30 | } catch { 31 | return nil 32 | } 33 | } 34 | 35 | func test_cpu() { 36 | guard let tests = loadFile(named: "cpu-test") else { 37 | XCTFail("No tests found") 38 | return 39 | } 40 | for test in tests { 41 | let parser = UAParser(agent: test.ua) 42 | let arch_found = parser.cpu?.identifier?.lowercased() 43 | let arch_exp = test.expect["architecture"]?.lowercased() 44 | guard arch_found == arch_exp else { 45 | XCTFail("Failed to test CPU. Expected \(arch_exp ?? ""), found \(arch_found ?? "")") 46 | return 47 | } 48 | } 49 | } 50 | 51 | func test_engines() { 52 | guard let tests = loadFile(named: "engines-test") else { 53 | XCTFail("No tests found") 54 | return 55 | } 56 | for test in tests { 57 | let parser = UAParser(agent: test.ua) 58 | let engine_name_found = parser.engine?.name?.lowercased() 59 | let engine_ver_found = parser.engine?.version?.lowercased() 60 | 61 | let engine_name_exp = test.expect["name"]?.lowercased() 62 | let engine_ver_exp = test.expect["version"]?.lowercased() 63 | 64 | guard engine_name_found == engine_name_exp, engine_ver_found == engine_ver_exp else { 65 | XCTFail("Failed to test Engines. Expected \(engine_name_exp ?? ""), found \(engine_name_found ?? ""), Expected version \(engine_ver_exp ?? "") - Found \(engine_ver_found ?? "")") 66 | return 67 | } 68 | } 69 | } 70 | 71 | func test_os() { 72 | guard let tests = loadFile(named: "os-test") else { 73 | XCTFail("No tests found") 74 | return 75 | } 76 | for test in tests { 77 | 78 | let parser = UAParser(agent: test.ua) 79 | let os_name_found = parser.os?.name?.lowercased() 80 | let os_ver_found = parser.os?.version?.lowercased() 81 | 82 | let os_name_exp = test.expect["name"]?.lowercased() 83 | let os_ver_exp = test.expect["version"]?.lowercased() 84 | 85 | guard os_name_found == os_name_exp, os_ver_found == os_ver_exp else { 86 | XCTFail("Failed to test OS. Expected \(os_name_exp ?? ""), found \(os_name_found ?? ""), Expected version \(os_ver_exp ?? "") - Found \(os_ver_found ?? "")") 87 | return 88 | } 89 | } 90 | } 91 | 92 | func test_device() { 93 | guard let tests = loadFile(named: "device-test") else { 94 | XCTFail("No tests found") 95 | return 96 | } 97 | for test in tests { 98 | 99 | let parser = UAParser(agent: test.ua) 100 | let f_vendor = parser.device?.vendor?.lowercased() 101 | let f_model = parser.device?.model?.lowercased() 102 | let f_type = parser.device?.type?.lowercased() 103 | 104 | let e_vendor = test.expect["vendor"]?.lowercased() 105 | let e_model = test.expect["model"]?.lowercased() 106 | let e_type = test.expect["type"]?.lowercased() 107 | 108 | if f_vendor != e_vendor || 109 | f_model != e_model || 110 | f_type != e_type { 111 | XCTFail("Failed to test device") 112 | } 113 | } 114 | } 115 | 116 | func test_browser() { 117 | guard let tests = loadFile(named: "browser-test") else { 118 | XCTFail("No tests found") 119 | return 120 | } 121 | for test in tests { 122 | 123 | let parser = UAParser(agent: test.ua) 124 | let f_name = parser.browser?.name?.lowercased() 125 | let f_version = parser.browser?.version?.lowercased() 126 | 127 | let e_name = test.expect["name"]?.lowercased() 128 | let e_version = test.expect["version"]?.lowercased() 129 | 130 | if f_name != e_name || 131 | f_version != e_version { 132 | XCTFail("Failed to test device") 133 | } 134 | } 135 | } 136 | 137 | static var allTests = [ 138 | ("test_cpu", test_cpu), 139 | ("test_engines", test_engines), 140 | ("test_os", test_os), 141 | ("test_device", test_device), 142 | ("test_browser", test_browser), 143 | ] 144 | } 145 | -------------------------------------------------------------------------------- /Tests/UAParserSwiftTests/browser-test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "desc" : "Android Browser on Galaxy Nexus", 4 | "ua" : "Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", 5 | "expect" : 6 | { 7 | "name" : "Android Browser", 8 | "version" : "4.0", 9 | } 10 | }, 11 | { 12 | "desc" : "Android Browser on Galaxy S3", 13 | "ua" : "Mozilla/5.0 (Linux; Android 4.4.4; en-us; SAMSUNG GT-I9300I Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36", 14 | "expect" : 15 | { 16 | "name" : "Android Browser", 17 | "version" : "1.5", 18 | } 19 | }, 20 | { 21 | "desc" : "Android Browser on HTC Flyer (P510E)", 22 | "ua" : "Mozilla/5.0 (Linux; U; Android 3.2.1; ru-ru; HTC Flyer P510e Build/HTK75C) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13", 23 | "expect" : 24 | { 25 | "name" : "Android Browser", 26 | "version" : "4.0", 27 | } 28 | }, 29 | { 30 | "desc" : "Android Browser on Huawei Honor Glory II (U9508)", 31 | "ua" : "Mozilla/5.0 (Linux; U; Android 4.0.4; ru-by; HUAWEI U9508 Build/HuaweiU9508) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 ACHEETAHI/2100050044", 32 | "expect" : 33 | { 34 | "name" : "Android Browser", 35 | "version" : "4.0", 36 | } 37 | }, 38 | { 39 | "desc" : "Android Browser on Huawei P8 (H891L)", 40 | "ua" : "Mozilla/5.0 (Linux; Android 4.4.4; HUAWEI H891L Build/HuaweiH891L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36", 41 | "expect" : 42 | { 43 | "name" : "Android Browser", 44 | "version" : "4.0", 45 | } 46 | }, 47 | { 48 | "desc" : "Android Browser on Samsung S6 (SM-G925F)", 49 | "ua" : "Mozilla/5.0 (Linux; Android 5.0.2; SAMSUNG SM-G925F Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.0 Chrome/38.0.2125.102 Mobile Safari/537.36", 50 | "expect" : 51 | { 52 | "name" : "SamsungBrowser", 53 | "version" : "3.0", 54 | } 55 | }, 56 | { 57 | "desc" : "Arora", 58 | "ua" : "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-CH) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2", 59 | "expect" : 60 | { 61 | "name" : "Arora", 62 | "version" : "0.2", 63 | } 64 | }, 65 | { 66 | "desc" : "Avant", 67 | "ua" : "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB5; Avant Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", 68 | "expect" : 69 | { 70 | "name" : "Avant", 71 | } 72 | }, 73 | { 74 | "desc" : "Baidu", 75 | "ua" : "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; baidubrowser 1.x)", 76 | "expect" : 77 | { 78 | "name" : "baidu", 79 | "version" : "1.x", 80 | } 81 | }, 82 | { 83 | "desc" : "Bolt", 84 | "ua" : "Mozilla/5.0 (X11; 78; CentOS; US-en) AppleWebKit/527+ (KHTML, like Gecko) Bolt/0.862 Version/3.0 Safari/523.15", 85 | "expect" : 86 | { 87 | "name" : "Bolt", 88 | "version" : "0.862", 89 | } 90 | }, 91 | { 92 | "desc" : "Bowser", 93 | "ua" : "Mozilla/5.0 (iOS; like Mac OS X) AppleWebKit/536.36 (KHTML, like Gecko) not Chrome/27.0.1500.95 Mobile/10B141 Safari/537.36 Bowser/0.2.1", 94 | "expect" : 95 | { 96 | "name" : "Bowser", 97 | "version" : "0.2.1", 98 | } 99 | }, 100 | { 101 | "desc" : "Camino", 102 | "ua" : "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en; rv:1.9.0.19) Gecko/2011091218 Camino/2.0.9 (like Firefox/3.0.19)", 103 | "expect" : 104 | { 105 | "name" : "Camino", 106 | "version" : "2.0.9", 107 | } 108 | }, 109 | { 110 | "desc" : "Chimera", 111 | "ua" : "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pl-PL; rv:1.0.1) Gecko/20021111 Chimera/0.6", 112 | "expect" : 113 | { 114 | "name" : "Chimera", 115 | "version" : "0.6", 116 | } 117 | }, 118 | { 119 | "desc" : "Chrome", 120 | "ua" : "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", 121 | "expect" : 122 | { 123 | "name" : "Chrome", 124 | "version" : "20.0.1090.0", 125 | } 126 | }, 127 | { 128 | "desc" : "Chrome Headless", 129 | "ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome Safari/537.36", 130 | "expect" : 131 | { 132 | "name" : "Chrome Headless", 133 | } 134 | }, 135 | { 136 | "desc" : "Chrome Headless", 137 | "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/60.0.3112.113 Safari/537.36", 138 | "expect" : 139 | { 140 | "name" : "Chrome Headless", 141 | "version" : "60.0.3112.113", 142 | } 143 | }, 144 | { 145 | "desc" : "Chrome WebView", 146 | "ua" : "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 5 Build/LMY48B; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/43.0.2357.65 Mobile Safari/537.36", 147 | "expect" : 148 | { 149 | "name" : "Chrome", 150 | "version" : "43.0.2357.65", 151 | } 152 | }, 153 | { 154 | "desc" : "Chrome on iOS", 155 | "ua" : "Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/7534.48.3", 156 | "expect" : 157 | { 158 | "name" : "Chrome", 159 | "version" : "19.0.1084.60", 160 | } 161 | }, 162 | { 163 | "desc" : "Chromium", 164 | "ua" : "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Ubuntu/11.10 Chromium/16.0.912.21 Chrome/16.0.912.21 Safari/535.7", 165 | "expect" : 166 | { 167 | "name" : "Chromium", 168 | "version" : "16.0.912.21", 169 | } 170 | }, 171 | { 172 | "desc" : "Chrome on Android", 173 | "ua" : "Mozilla/5.0 (Linux; U; Android-4.0.3; en-us; Galaxy Nexus Build/IML74K) AppleWebKit/535.7 (KHTML, like Gecko) CrMo/16.0.912.75 Mobile Safari/535.7", 174 | "expect" : 175 | { 176 | "name" : "Chrome", 177 | "version" : "16.0.912.75", 178 | } 179 | }, 180 | { 181 | "desc" : "Dillo", 182 | "ua" : "Dillo/2.2", 183 | "expect" : 184 | { 185 | "name" : "Dillo", 186 | "version" : "2.2", 187 | } 188 | }, 189 | { 190 | "desc" : "Dolphin", 191 | "ua" : "Mozilla/5.0 (SCH-F859/F859DG12;U;NUCLEUS/2.1;Profile/MIDP-2.1 Configuration/CLDC-1.1;480*800;CTC/2.0) Dolfin/2.0", 192 | "expect" : 193 | { 194 | "name" : "Dolphin", 195 | "version" : "2.0", 196 | } 197 | }, 198 | { 199 | "desc" : "Doris", 200 | "ua" : "Doris/1.15 [en] (Symbian)", 201 | "expect" : 202 | { 203 | "name" : "Doris", 204 | "version" : "1.15", 205 | } 206 | }, 207 | { 208 | "desc" : "Epiphany", 209 | "ua" : "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040628 Epiphany/1.2.6", 210 | "expect" : 211 | { 212 | "name" : "Epiphany", 213 | "version" : "1.2.6", 214 | } 215 | }, 216 | { 217 | "desc" : "Facebook in-App Browser for Android", 218 | "ua" : "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/43.0.2357.121 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/35.0.0.48.273;]", 219 | "expect" : 220 | { 221 | "name" : "Facebook", 222 | "version" : "35.0.0.48.273", 223 | } 224 | }, 225 | { 226 | "desc" : "Facebook in-App Browser for iOS", 227 | "ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E304 [FBAN/FBIOS;FBAV/91.0.0.41.73;FBBV/57050710;FBDV/iPhone8,1;FBMD/iPhone;FBSN/iOS;FBSV/10.3.1;FBSS/2;FBCR/Telekom.de;FBID/phone;FBLC/de_DE;FBOP/5;FBRV/0])", 228 | "expect" : 229 | { 230 | "name" : "Facebook", 231 | "version" : "91.0.0.41.73", 232 | } 233 | }, 234 | { 235 | "desc" : "Firebird", 236 | "ua" : "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031007 Firebird/0.7", 237 | "expect" : 238 | { 239 | "name" : "Firebird", 240 | "version" : "0.7", 241 | } 242 | }, 243 | { 244 | "desc" : "Firefox", 245 | "ua" : "Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2", 246 | "expect" : 247 | { 248 | "name" : "Firefox", 249 | "version" : "15.0a2", 250 | } 251 | }, 252 | { 253 | "desc" : "Fennec", 254 | "ua" : "Mozilla/5.0 (X11; U; Linux armv61; en-US; rv:1.9.1b2pre) Gecko/20081015 Fennec/1.0a1", 255 | "expect" : 256 | { 257 | "name" : "Fennec", 258 | "version" : "1.0a1", 259 | } 260 | }, 261 | { 262 | "desc" : "Flock", 263 | "ua" : "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008100716 Firefox/3.0.3 Flock/2.0", 264 | "expect" : 265 | { 266 | "name" : "Flock", 267 | "version" : "2.0", 268 | } 269 | }, 270 | { 271 | "desc" : "GoBrowser", 272 | "ua" : "Nokia5700XpressMusic/GoBrowser/1.6.91", 273 | "expect" : 274 | { 275 | "name" : "GoBrowser", 276 | "version" : "1.6.91", 277 | } 278 | }, 279 | { 280 | "desc" : "IceApe", 281 | "ua" : "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.19) Gecko/20110817 Iceape/2.0.14", 282 | "expect" : 283 | { 284 | "name" : "Iceape", 285 | "version" : "2.0.14", 286 | } 287 | }, 288 | { 289 | "desc" : "IceCat", 290 | "ua" : "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092921 IceCat/3.0.3-g1", 291 | "expect" : 292 | { 293 | "name" : "IceCat", 294 | "version" : "3.0.3-g1", 295 | } 296 | }, 297 | { 298 | "desc" : "Iceweasel", 299 | "ua" : "Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.16) Gecko/2009121610 Iceweasel/3.0.6 (Debian-3.0.6-3)", 300 | "expect" : 301 | { 302 | "name" : "Iceweasel", 303 | "version" : "3.0.6", 304 | } 305 | }, 306 | { 307 | "desc" : "iCab", 308 | "ua" : "iCab/2.9.5 (Macintosh; U; PPC; Mac OS X)", 309 | "expect" : 310 | { 311 | "name" : "iCab", 312 | "version" : "2.9.5", 313 | } 314 | }, 315 | { 316 | "desc" : "IEMobile", 317 | "ua" : "Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11) 320x240; VZW; Motorola-Q9c; Windows Mobile 6.1 Standard", 318 | "expect" : 319 | { 320 | "name" : "IEMobile", 321 | "version" : "7.11", 322 | } 323 | }, 324 | { 325 | "desc" : "IE 11 with IE token", 326 | "ua" : "Mozilla/5.0 (IE 11.0; Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko", 327 | "expect" : 328 | { 329 | "name" : "IE", 330 | "version" : "11.0", 331 | } 332 | }, 333 | { 334 | "desc" : "IE 11 without IE token", 335 | "ua" : "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv 11.0) like Gecko", 336 | "expect" : 337 | { 338 | "name" : "IE", 339 | "version" : "11.0", 340 | } 341 | }, 342 | { 343 | "desc" : "K-Meleon", 344 | "ua" : "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2", 345 | "expect" : 346 | { 347 | "name" : "K-Meleon", 348 | "version" : "0.8.2", 349 | } 350 | }, 351 | { 352 | "desc" : "Kindle Browser", 353 | "ua" : "Mozilla/4.0 (compatible; Linux 2.6.22) NetFront/3.4 Kindle/2.5 (screen 600x800; rotate)", 354 | "expect" : 355 | { 356 | "name" : "Kindle", 357 | "version" : "2.5", 358 | } 359 | }, 360 | { 361 | "desc" : "Konqueror", 362 | "ua" : "Mozilla/5.0 (compatible; Konqueror/3.5; Linux; X11; x86_64) KHTML/3.5.6 (like Gecko) (Kubuntu)", 363 | "expect" : 364 | { 365 | "name" : "KHTML", 366 | "version" : "3.5.6", 367 | } 368 | }, 369 | { 370 | "desc" : "Lunascape", 371 | "ua" : "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090804 Firefox/3.5.2 Lunascape/5.1.4.5", 372 | "expect" : 373 | { 374 | "name" : "Lunascape", 375 | "version" : "5.1.4.5", 376 | } 377 | }, 378 | { 379 | "desc" : "Lynx", 380 | "ua" : "Lynx/2.8.5dev.16 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6b", 381 | "expect" : 382 | { 383 | "name" : "Lynx", 384 | "version" : "2.8.5dev.16", 385 | } 386 | }, 387 | { 388 | "desc" : "Maemo Browser", 389 | "ua" : "Mozilla/5.0 (X11; U; Linux armv7l; ru-RU; rv:1.9.2.3pre) Gecko/20100723 Firefox/3.5 Maemo Browser 1.7.4.8 RX-51 N900", 390 | "expect" : 391 | { 392 | "name" : "Maemo Browser", 393 | "version" : "1.7.4.8", 394 | } 395 | }, 396 | { 397 | "desc" : "Maxthon", 398 | "ua" : "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)", 399 | "expect" : 400 | { 401 | "name" : "Maxthon", 402 | } 403 | }, 404 | { 405 | "desc" : "Midori", 406 | "ua" : "Midori/0.2.2 (X11; Linux i686; U; en-us) WebKit/531.2+", 407 | "expect" : 408 | { 409 | "name" : "Midori", 410 | "version" : "0.2.2", 411 | } 412 | }, 413 | { 414 | "desc" : "Minimo", 415 | "ua" : "Mozilla/5.0 (X11; U; Linux armv6l; rv 1.8.1.5pre) Gecko/20070619 Minimo/0.020", 416 | "expect" : 417 | { 418 | "name" : "Minimo", 419 | "version" : "0.020", 420 | } 421 | }, 422 | { 423 | "desc" : "MIUI Browser on Xiaomi Hongmi WCDMA (HM2013023)", 424 | "ua" : "Mozilla/5.0 (Linux; U; Android 4.2.2; ru-ru; 2013023 Build/HM2013023) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0", 425 | "expect" : 426 | { 427 | "name" : "MIUI Browser", 428 | "version" : "1.0", 429 | } 430 | }, 431 | { 432 | "desc" : "Mobile Safari", 433 | "ua" : "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7", 434 | "expect" : 435 | { 436 | "name" : "Mobile Safari", 437 | "version" : "4.0.5", 438 | } 439 | }, 440 | { 441 | "desc" : "Mosaic", 442 | "ua" : "NCSA_Mosaic/2.6 (X11; SunOS 4.1.3 sun4m)", 443 | "expect" : 444 | { 445 | "name" : "Mosaic", 446 | "version" : "2.6", 447 | } 448 | }, 449 | { 450 | "desc" : "Mozilla", 451 | "ua" : "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20070606", 452 | "expect" : 453 | { 454 | "name" : "Mozilla", 455 | "version" : "5.0", 456 | } 457 | }, 458 | { 459 | "desc" : "MSIE", 460 | "ua" : "Mozilla/4.0 (compatible; MSIE 5.0b1; Mac_PowerPC)", 461 | "expect" : 462 | { 463 | "name" : "IE", 464 | "version" : "5.0b1", 465 | } 466 | }, 467 | { 468 | "desc" : "NetFront", 469 | "ua" : "Mozilla/4.0 (PDA; Windows CE/1.0.1) NetFront/3.0", 470 | "expect" : 471 | { 472 | "name" : "NetFront", 473 | "version" : "3.0", 474 | } 475 | }, 476 | { 477 | "desc" : "Netscape on Windows ME", 478 | "ua" : "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8.1.8pre) Gecko/20071015 Firefox/2.0.0.7 Navigator/9.0", 479 | "expect" : 480 | { 481 | "name" : "Netscape", 482 | "version" : "9.0", 483 | } 484 | }, 485 | { 486 | "desc" : "Netscape on Windows 2000", 487 | "ua" : "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20050519 Netscape/8.0.1", 488 | "expect" : 489 | { 490 | "name" : "Netscape", 491 | "version" : "8.0.1", 492 | } 493 | }, 494 | { 495 | "desc" : "Nokia Browser", 496 | "ua" : "Mozilla/5.0 (Symbian/3; Series60/5.2 NokiaN8-00/025.007; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/533.4 (KHTML, like Gecko) NokiaBrowser/7.3.1.37 Mobile Safari/533.4 3gpp-gba", 497 | "expect" : 498 | { 499 | "name" : "NokiaBrowser", 500 | "version" : "7.3.1.37", 501 | } 502 | }, 503 | { 504 | "desc" : "Oculus Browser", 505 | "ua" : "Mozilla/5.0 (Linux; Android 7.0; SM-G920I Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/3.4.9 SamsungBrowser/4.0 Chrome/57.0.2987.146 Mobile VR Safari/537.36", 506 | "expect" : 507 | { 508 | "name" : "OculusBrowser", 509 | "version" : "3.4.9", 510 | } 511 | }, 512 | { 513 | "desc" : "OmniWeb", 514 | "ua" : "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.48", 515 | "expect" : 516 | { 517 | "name" : "OmniWeb", 518 | "version" : "558.48", 519 | } 520 | }, 521 | { 522 | "desc" : "Opera > 9.80", 523 | "ua" : "Opera/9.80 (X11; Linux x86_64; U; Linux Mint; en) Presto/2.2.15 Version/10.10", 524 | "expect" : 525 | { 526 | "name" : "Opera", 527 | "version" : "10.10", 528 | } 529 | }, 530 | { 531 | "desc" : "Opera < 9.80 on Windows", 532 | "ua" : "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95) Opera 6.01 [en]", 533 | "expect" : 534 | { 535 | "name" : "Opera", 536 | "version" : "6.01", 537 | } 538 | }, 539 | { 540 | "desc" : "Opera < 9.80 on OSX", 541 | "ua" : "Opera/8.5 (Macintosh; PPC Mac OS X; U; en)", 542 | "expect" : 543 | { 544 | "name" : "Opera", 545 | "version" : "8.5", 546 | } 547 | }, 548 | { 549 | "desc" : "Opera Mobile", 550 | "ua" : "Opera/9.80 (Android 2.3.5; Linux; Opera Mobi/ADR-1111101157; U; de) Presto/2.9.201 Version/11.50", 551 | "expect" : 552 | { 553 | "name" : "Opera Mobi", 554 | "version" : "11.50", 555 | } 556 | }, 557 | { 558 | "desc" : "Opera Webkit", 559 | "ua" : "Mozilla/5.0 AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.123 Mobile Safari/537.22 OPR/14.0.1025.52315", 560 | "expect" : 561 | { 562 | "name" : "Opera", 563 | "version" : "14.0.1025.52315", 564 | } 565 | }, 566 | { 567 | "desc" : "Opera Mini", 568 | "ua" : "Opera/9.80 (J2ME/MIDP; Opera Mini/5.1.21214/19.916; U; en) Presto/2.5.25", 569 | "expect" : 570 | { 571 | "name" : "Opera Mini", 572 | "version" : "5.1.21214", 573 | } 574 | }, 575 | { 576 | "desc" : "Opera Mini 8 above on iPhone", 577 | "ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) OPiOS/12.1.1.98980 Mobile/13C75 Safari/9537.53", 578 | "expect" : 579 | { 580 | "name" : "Opera Mini", 581 | "version" : "12.1.1.98980", 582 | } 583 | }, 584 | { 585 | "desc" : "Opera Tablet", 586 | "ua" : "Opera/9.80 (Windows NT 6.1; Opera Tablet/15165; U; en) Presto/2.8.149 Version/11.1", 587 | "expect" : 588 | { 589 | "name" : "Opera Tablet", 590 | "version" : "11.1", 591 | } 592 | }, 593 | { 594 | "desc" : "Opera Coast", 595 | "ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_2 like Mac OS X; en) AppleWebKit/601.1.46 (KHTML, like Gecko) Coast/5.04.110603 Mobile/13F69 Safari/7534.48.3", 596 | "expect" : 597 | { 598 | "name" : "Opera Coast", 599 | "version" : "5.04.110603", 600 | } 601 | }, 602 | { 603 | "desc" : "PhantomJS", 604 | "ua" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.2 Safari/534.34", 605 | "expect" : 606 | { 607 | "name" : "PhantomJS", 608 | "version" : "1.9.2", 609 | } 610 | }, 611 | { 612 | "desc" : "Phoenix", 613 | "ua" : "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2b) Gecko/20021029 Phoenix/0.4", 614 | "expect" : 615 | { 616 | "name" : "Phoenix", 617 | "version" : "0.4", 618 | } 619 | }, 620 | { 621 | "desc" : "Polaris", 622 | "ua" : "LG-LX600 Polaris/6.0 MMP/2.0 Profile/MIDP-2.1 Configuration/CLDC-1.1", 623 | "expect" : 624 | { 625 | "name" : "Polaris", 626 | "version" : "6.0", 627 | } 628 | }, 629 | { 630 | "desc" : "QQ", 631 | "ua" : "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; OPPO R7s Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/37.0.0.0 MQQBrowser/7.1 Mobile Safari/537.36", 632 | "expect" : 633 | { 634 | "name" : "QQBrowser", 635 | "version" : "7.1", 636 | } 637 | }, 638 | { 639 | "desc" : "RockMelt", 640 | "ua" : "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) RockMelt/0.8.36.78 Chrome/7.0.517.44 Safari/534.7", 641 | "expect" : 642 | { 643 | "name" : "RockMelt", 644 | "version" : "0.8.36.78", 645 | } 646 | }, 647 | { 648 | "desc" : "Safari", 649 | "ua" : "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8", 650 | "expect" : 651 | { 652 | "name" : "Safari", 653 | "version" : "5.0.1", 654 | } 655 | }, 656 | { 657 | "desc" : "Safari < 3.0", 658 | "ua" : "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/419 (KHTML, like Gecko) Safari/419.3", 659 | "expect" : 660 | { 661 | "name" : "Safari", 662 | "version" : "2.0.4", 663 | } 664 | }, 665 | { 666 | "desc" : "Samsung Browser", 667 | "ua" : "Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG-SM-G925A Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Mobile Safari/537.36", 668 | "expect" : 669 | { 670 | "name" : "SamsungBrowser", 671 | "version" : "4.0", 672 | } 673 | }, 674 | { 675 | "desc" : "SeaMonkey", 676 | "ua" : "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b4pre) Gecko/20090405 SeaMonkey/2.0b1pre", 677 | "expect" : 678 | { 679 | "name" : "SeaMonkey", 680 | "version" : "2.0b1pre", 681 | } 682 | }, 683 | { 684 | "desc" : "Silk Browser", 685 | "ua" : "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.1.0-84)", 686 | "expect" : 687 | { 688 | "name" : "Silk", 689 | "version" : "1.1.0-84", 690 | } 691 | }, 692 | { 693 | "desc" : "Skyfire", 694 | "ua" : "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Safari/530.17 Skyfire/2.0", 695 | "expect" : 696 | { 697 | "name" : "Skyfire", 698 | "version" : "2.0", 699 | } 700 | }, 701 | { 702 | "desc" : "SlimBrowser", 703 | "ua" : "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SlimBrowser)", 704 | "expect" : 705 | { 706 | "name" : "Slim", 707 | } 708 | }, 709 | { 710 | "desc" : "Swiftfox", 711 | "ua" : "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061024 Firefox/2.0 (Swiftfox)", 712 | "expect" : 713 | { 714 | "name" : "Swiftfox", 715 | } 716 | }, 717 | { 718 | "desc" : "Tizen Browser", 719 | "ua" : "Mozilla/5.0 (Linux; U; Tizen/1.0 like Android; en-us; AppleWebKit/534.46 (KHTML, like Gecko) Tizen Browser/1.0 Mobile", 720 | "expect" : 721 | { 722 | "name" : "Tizen Browser", 723 | "version" : "1.0", 724 | } 725 | }, 726 | { 727 | "desc" : "UC Browser", 728 | "ua" : "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 UBrowser/5.6.12860.7 Safari/537.36", 729 | "expect" : 730 | { 731 | "name" : "UCBrowser", 732 | "version" : "5.6.12860.7", 733 | } 734 | }, 735 | { 736 | "desc" : "UC Browser", 737 | "ua" : "Mozilla/5.0 (Linux; U; Android 6.0.1; en-US; Lenovo P2a42 Build/MMB29M) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 UCBrowser/11.2.0.915 U3/0.8.0 Mobile Safari/534.30", 738 | "expect" : 739 | { 740 | "name" : "UCBrowser", 741 | "version" : "11.2.0.915", 742 | } 743 | }, 744 | { 745 | "desc" : "UC Browser on Samsung", 746 | "ua" : "Mozilla/5.0 (Java; U; Pt-br; samsung-gt-s5620) UCBrowser8.2.1.144/69/352/UCWEB Mobile UNTRUSTED/1.0", 747 | "expect" : 748 | { 749 | "name" : "UCBrowser", 750 | "version" : "8.2.1.144", 751 | } 752 | }, 753 | { 754 | "desc" : "UC Browser on Nokia", 755 | "ua" : "Mozilla/5.0 (S60V3; U; en-in; NokiaN73)/UC Browser8.4.0.159/28/351/UCWEB Mobile", 756 | "expect" : 757 | { 758 | "name" : "UCBrowser", 759 | "version" : "8.4.0.159", 760 | } 761 | }, 762 | { 763 | "desc" : "UC Browser J2ME", 764 | "ua" : "UCWEB/2.0 (MIDP-2.0; U; zh-CN; HTC EVO 3D X515m) U2/1.0.0 UCBrowser/10.4.0.558 U2/1.0.0 Mobile", 765 | "expect" : 766 | { 767 | "name" : "UCBrowser", 768 | "version" : "10.4.0.558", 769 | } 770 | }, 771 | { 772 | "desc" : "UC Browser J2ME 2", 773 | "ua" : "JUC (Linux; U; 2.3.5; zh-cn; GT-I9100; 480*800) UCWEB7.9.0.94/139/800", 774 | "expect" : 775 | { 776 | "name" : "UCBrowser", 777 | "version" : "7.9.0.94", 778 | } 779 | }, 780 | { 781 | "desc": "WeChat on iOS", 782 | "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 8_4_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12H321 MicroMessenger/6.3.6 NetType/WIFI Language/zh_CN", 783 | "expect": 784 | { 785 | "name": "WeChat", 786 | "version": "6.3.6", 787 | } 788 | }, 789 | { 790 | "desc": "WeChat on Android", 791 | "ua": "Mozilla/5.0 (Linux; U; Android 5.1; zh-cn; Lenovo K50-t5 Build/LMY47D) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.4 TBS/025478 Mobile Safari/533.1 MicroMessenger/6.3.5.50_r1573191.640 NetType/WIFI Language/zh_CN", 792 | "expect": 793 | { 794 | "name": "WeChat", 795 | "version": "6.3.5.50_r1573191.640", 796 | } 797 | }, 798 | { 799 | "desc" : "Vivaldi", 800 | "ua" : "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.89 Vivaldi/1.0.83.38 Safari/537.36", 801 | "expect" : 802 | { 803 | "name" : "Vivaldi", 804 | "version" : "1.0.83.38", 805 | } 806 | }, 807 | { 808 | "desc" : "Yandex", 809 | "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/536.5 (KHTML, like Gecko) YaBrowser/1.0.1084.5402 Chrome/19.0.1084.5402 Safari/536.5", 810 | "expect" : 811 | { 812 | "name" : "Yandex", 813 | "version" : "1.0.1084.5402", 814 | } 815 | }, 816 | { 817 | "desc" : "Puffin", 818 | "ua" : "Mozilla/5.0 (Linux; Android 6.0.1; Lenovo P2a42 Build/MMB29M; en-us) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Puffin/6.0.8.15804AP", 819 | "expect" : 820 | { 821 | "name" : "Puffin", 822 | "version" : "6.0.8.15804AP", 823 | } 824 | }, 825 | { 826 | "desc" : "Microsoft Edge", 827 | "ua" : "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0", 828 | "expect" : 829 | { 830 | "name" : "Edge", 831 | "version" : "12.0", 832 | } 833 | }, 834 | { 835 | "desc" : "Iridium", 836 | "ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Iridium/43.8 Safari/537.36 Chrome/43.0.2357.132", 837 | "expect" : 838 | { 839 | "name" : "Iridium", 840 | "version" : "43.8", 841 | } 842 | }, 843 | { 844 | "desc" : "Firefox iOS", 845 | "ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) FxiOS/1.1 Mobile/13B143 Safari/601.1.46", 846 | "expect" : 847 | { 848 | "name" : "Firefox", 849 | "version" : "1.1", 850 | } 851 | }, 852 | { 853 | "desc" : "QQ on iOS", 854 | "ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Mobile/14A456 QQ/6.5.3.410 V1_IPH_SQ_6.5.3_1_APP_A Pixel/1080 Core/UIWebView NetType/WIFI Mem/26", 855 | "expect" : 856 | { 857 | "name" : "QQ", 858 | "version" : "6.5.3.410", 859 | } 860 | }, 861 | { 862 | "desc" : "QQ on Android", 863 | "ua" : "Mozilla/5.0 (Linux; Android 6.0; PRO 6 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/37.0.0.0 Mobile MQQBrowser/6.8 TBS/036824 Safari/537.36 V1_AND_SQ_6.5.8_422_YYB_D PA QQ/6.5.8.2910 NetType/WIFI WebP/0.3.0 Pixel/1080", 864 | "expect" : 865 | { 866 | "name" : "QQ", 867 | "version" : "6.5.8.2910", 868 | } 869 | }, 870 | { 871 | "desc" : "GSA on iOS", 872 | "ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) GSA/30.1.161623614 Mobile/14F89 Safari/602.1", 873 | "expect" : 874 | { 875 | "name" : "GSA", 876 | "version" : "30.1.161623614", 877 | } 878 | } 879 | ] 880 | -------------------------------------------------------------------------------- /Tests/UAParserSwiftTests/cpu-test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "desc" : "i686", 4 | "ua" : "Mozilla\/5.0 (X11; Ubuntu; Linux i686; rv:19.0) Gecko\/20100101 Firefox\/19.0", 5 | "expect" : { 6 | "architecture" : "ia32" 7 | } 8 | }, 9 | { 10 | "desc" : "i386", 11 | "ua" : "Mozilla\/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko\/20040628 Epiphany\/1.2.6", 12 | "expect" : { 13 | "architecture" : "ia32" 14 | } 15 | }, 16 | { 17 | "desc" : "x86-64", 18 | "ua" : "Opera\/9.80 (X11; Linux x86_64; U; Linux Mint; en) Presto\/2.2.15 Version\/10.10", 19 | "expect" : { 20 | "architecture" : "amd64" 21 | } 22 | }, 23 | { 24 | "desc" : "win64", 25 | "ua" : "Mozilla\/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Win64; x64; Trident\/6.0; .NET4.0E; .NET4.0C)", 26 | "expect" : { 27 | "architecture" : "amd64" 28 | } 29 | }, 30 | { 31 | "desc" : "WOW64", 32 | "ua" : "Mozilla\/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident\/6.0)", 33 | "expect" : { 34 | "architecture" : "amd64" 35 | } 36 | }, 37 | { 38 | "desc" : "ARMv6", 39 | "ua" : "Mozilla\/5.0 (X11; U; Linux armv61; en-US; rv:1.9.1b2pre) Gecko\/20081015 Fennec\/1.0a1", 40 | "expect" : { 41 | "architecture" : "arm" 42 | } 43 | }, 44 | { 45 | "desc" : "Pocket PC", 46 | "ua" : "Opera\/9.7 (Windows Mobile; PPC; Opera Mobi\/35166; U; en) Presto\/2.2.1", 47 | "expect" : { 48 | "architecture" : "arm" 49 | } 50 | }, 51 | { 52 | "desc" : "Mac PowerPC", 53 | "ua" : "Mozilla\/4.0 (compatible; MSIE 4.5; Mac_PowerPC)", 54 | "expect" : { 55 | "architecture" : "ppc" 56 | } 57 | }, 58 | { 59 | "desc" : "Mac PowerPC", 60 | "ua" : "Mozilla\/4.0 (compatible; MSIE 5.17; Mac_PowerPC Mac OS; en)", 61 | "expect" : { 62 | "architecture" : "ppc" 63 | } 64 | }, 65 | { 66 | "desc" : "Mac PowerPC", 67 | "ua" : "iCab\/2.9.5 (Macintosh; U; PPC; Mac OS X)", 68 | "expect" : { 69 | "architecture" : "ppc" 70 | } 71 | }, 72 | { 73 | "desc" : "UltraSPARC", 74 | "ua" : "Mozilla\/5.0 (X11; U; SunOS sun4u; en-US; rv:1.9b5) Gecko\/2008032620 Firefox\/3.0b5", 75 | "expect" : { 76 | "architecture" : "sparc" 77 | } 78 | }, 79 | { 80 | "desc" : "QuickTime", 81 | "ua" : "QuickTime\/7.5.6 (qtver=7.5.6;cpu=IA32;os=Mac 10.5.8)", 82 | "expect" : { 83 | "architecture" : "ia32" 84 | } 85 | }, 86 | { 87 | "desc" : "XBMC", 88 | "ua" : "XBMC\/12.0 Git:20130127-fb595f2 (Windows NT 6.1;WOW64;Win64;x64; http:\/\/www.xbmc.org)", 89 | "expect" : { 90 | "architecture" : "amd64" 91 | } 92 | } 93 | ] -------------------------------------------------------------------------------- /Tests/UAParserSwiftTests/device-test.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "desc": "Asus Nexus 7", 3 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 7 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Safari/537.36", 4 | "expect": { 5 | "vendor": "Asus", 6 | "model": "Nexus 7", 7 | "type": "tablet" 8 | } 9 | }, 10 | { 11 | "desc": "Asus Padfone", 12 | "ua": "Mozilla/5.0 (Linux; Android 4.1.1; PadFone 2 Build/JRO03L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.117 Safari/537.36", 13 | "expect": { 14 | "vendor": "Asus", 15 | "model": "PadFone", 16 | "type": "tablet" 17 | } 18 | }, 19 | { 20 | "desc": "Desktop (IE11 with Tablet string)", 21 | "ua": "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; Tablet PC 2.0; GWX:MANAGED; rv:11.0) like Gecko", 22 | "expect": { 23 | } 24 | }, 25 | { 26 | "desc": "HTC Evo Shift 4G", 27 | "ua": "Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; HTC APA7373KT Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0", 28 | "expect": { 29 | "vendor": "HTC", 30 | "model": "APA7373KT", 31 | "type": "mobile" 32 | } 33 | }, 34 | { 35 | "desc": "HTC Nexus 9", 36 | "ua": "Mozilla/5.0 (Linux; Android 5.0; Nexus 9 Build/LRX21R) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Mobile Crosswalk/7.36.154.13 Safari/537.36", 37 | "expect": { 38 | "vendor": "HTC", 39 | "model": "Nexus 9", 40 | "type": "tablet" 41 | } 42 | }, 43 | { 44 | "desc": "Huawei Honor", 45 | "ua": "Mozilla/5.0 (Linux; U; Android 2.3; xx-xx; U8860 Build/HuaweiU8860) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", 46 | "expect": { 47 | "vendor": "Huawei", 48 | "model": "U8860", 49 | "type": "mobile" 50 | } 51 | }, 52 | { 53 | "desc": "Huawei Nexus 6P", 54 | "ua": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 6P Build/MTC19V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Mobile Safari/537", 55 | "expect": { 56 | "vendor": "Huawei", 57 | "model": "Nexus 6P", 58 | "type": "mobile" 59 | } 60 | }, 61 | { 62 | "desc": "Huawei P10", 63 | "ua": "Mozilla/5.0 (Linux; Android 7.0; VTR-L09 Build/HUAWEIVTR-L09; xx-xx) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Mobile Safari/537.36", 64 | "expect": { 65 | "vendor": "Huawei", 66 | "model": "VTR-L09", 67 | "type": "mobile" 68 | } 69 | }, 70 | { 71 | "desc": "Huawei Y3II", 72 | "ua": "Mozilla/5.0 (Linux; U; Android 5.1; xx-xx; HUAWEI LUA-L03 Build/HUAWEILUA-L03) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36", 73 | "expect": { 74 | "vendor": "Huawei", 75 | "model": "LUA-L03", 76 | "type": "mobile" 77 | } 78 | }, 79 | { 80 | "desc": "iPod", 81 | "ua": "Mozilla/5.0 (iPod touch; CPU iPhone OS 7_0_4 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B554a Safari/9537.53", 82 | "expect": { 83 | "vendor": "Apple", 84 | "model": "iPod touch", 85 | "type": "mobile" 86 | } 87 | }, 88 | { 89 | "desc": "LG Nexus 4", 90 | "ua": "Mozilla/5.0 (Linux; Android 4.2.1; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19", 91 | "expect": { 92 | "vendor": "LG", 93 | "model": "Nexus 4", 94 | "type": "mobile" 95 | } 96 | }, 97 | { 98 | "desc": "LG Nexus 5", 99 | "ua": "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19", 100 | "expect": { 101 | "vendor": "LG", 102 | "model": "Nexus 5", 103 | "type": "mobile" 104 | } 105 | }, 106 | { 107 | "desc": "Meizu M5 Note", 108 | "ua": "Mozilla/5.0 (Linux; Android 6.0; M5 Note Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043024 Safari/537.36 MicroMessenger/6.5.7.1040 NetType/WIFI Language/zh_CN", 109 | "expect": { 110 | "vendor": "Meizu", 111 | "model": "M5 Note", 112 | "type": "tablet" 113 | } 114 | }, 115 | { 116 | "desc": "Microsoft Lumia 950", 117 | "ua": "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586", 118 | "expect": { 119 | "vendor": "Microsoft", 120 | "model": "Lumia 950", 121 | "type": "mobile" 122 | } 123 | }, 124 | { 125 | "desc": "Motorola Moto X", 126 | "ua": "Mozilla/5.0 (Linux; Android 4.4.4; XT1097 Build/KXE21.187-38) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.109 Mobile Safari/537.36", 127 | "expect": { 128 | "vendor": "Motorola", 129 | "model": "XT1097", 130 | "type": "mobile" 131 | } 132 | }, 133 | { 134 | "desc": "Motorola Nexus 6", 135 | "ua": "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.20 Mobile Safari/537.36", 136 | "expect": { 137 | "vendor": "Motorola", 138 | "model": "Nexus 6", 139 | "type": "mobile" 140 | } 141 | }, 142 | { 143 | "desc": "Motorola Droid RAZR 4G", 144 | "ua": "Mozilla/5.0 (Linux; U; Android 2.3; xx-xx; DROID RAZR 4G Build/6.5.1-73_DHD-11_M1-29) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", 145 | "expect": { 146 | "vendor": "Motorola", 147 | "model": "DROID RAZR 4G", 148 | "type": "mobile" 149 | } 150 | }, 151 | { 152 | "desc": "iPhone", 153 | "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53", 154 | "expect": { 155 | "vendor": "Apple", 156 | "model": "iPhone", 157 | "type": "mobile" 158 | } 159 | }, 160 | { 161 | "desc": "Motorola Droid RAZR 4G", 162 | "ua": "Mozilla/5.0 (iPod touch; CPU iPhone OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A501 Safari/9537.53", 163 | "expect": { 164 | "vendor": "Apple", 165 | "model": "iPod touch", 166 | "type": "mobile" 167 | } 168 | }, 169 | { 170 | "desc": "Moto X", 171 | "ua": "Mozilla/5.0 (Linux; U; Android 4.2; xx-xx; XT1058 Build/13.9.0Q2.X-70-GHOST-ATT_LE-2) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", 172 | "expect": { 173 | "vendor": "Motorola", 174 | "model": "XT1058", 175 | "type": "mobile" 176 | } 177 | }, 178 | { 179 | "desc": "Nokia3xx", 180 | "ua": "Nokia303/14.87 CLDC-1.1", 181 | "expect": { 182 | "vendor": "Nokia", 183 | "model": "303", 184 | "type": "mobile" 185 | } 186 | }, 187 | { 188 | "desc": "OnePlus One", 189 | "ua": "Mozilla/5.0 (Linux; Android 4.4.4; A0001 Build/KTU84Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.59 Mobile Safari/537.36", 190 | "expect": { 191 | "vendor": "OnePlus", 192 | "model": "1", 193 | "type": "mobile" 194 | } 195 | }, 196 | { 197 | "desc": "OPPO R7s", 198 | "ua": "Mozilla/5.0 (Linux; U; Android 4.4.4; zh-cn; OPPO R7s Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/37.0.0.0 MQQBrowser/7.1 Mobile Safari/537.36", 199 | "expect": { 200 | "vendor": "OPPO", 201 | "model": "R7s", 202 | "type": "mobile" 203 | } 204 | }, 205 | { 206 | "desc": "Philips SmartTV", 207 | "ua": "Opera/9.80 HbbTV/1.1.1 (; Philips; ; ; ; ) NETTV/4.0.2; en) Version/11.60", 208 | "expect": { 209 | "vendor": "Philips", 210 | "model": "", 211 | "type": "smarttv" 212 | } 213 | }, 214 | { 215 | "desc": "Kindle Fire HD", 216 | "ua": "Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; KFTT Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.4 Mobile Safari/535.19 Silk-Accelerated=true", 217 | "expect": { 218 | "vendor": "Amazon", 219 | "model": "KFTT", 220 | "type": "tablet" 221 | } 222 | }, 223 | { 224 | "desc": "Samsung Galaxy Note 8", 225 | "ua": "Mozilla/5.0 (Linux; Android 4.2.2; GT-N5100 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Safari/537.36", 226 | "expect": { 227 | "vendor": "Samsung", 228 | "model": "GT-N5100", 229 | "type": "tablet" 230 | } 231 | }, 232 | { 233 | "desc": "Samsung SM-C5000", 234 | "ua": "Mozilla/5.0 (Linux; Android 6.0.1; SM-C5000 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36 wkbrowser 4.1.35 3065", 235 | "expect": { 236 | "vendor": "Samsung", 237 | "model": "SM-C5000", 238 | "type": "mobile" 239 | } 240 | }, 241 | { 242 | "desc": "Samsung SM-T231", 243 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; SM-T231 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Safari/537.36", 244 | "expect": { 245 | "vendor": "Samsung", 246 | "model": "SM-T231", 247 | "type": "tablet" 248 | } 249 | }, 250 | { 251 | "desc": "Samsung SM-T700", 252 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; SM-T700 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Safari/537.36", 253 | "expect": { 254 | "vendor": "Samsung", 255 | "model": "SM-T700", 256 | "type": "tablet" 257 | } 258 | }, 259 | { 260 | "desc": "Samsung SM-T520", 261 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; SM-T520 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Safari/537.36", 262 | "expect": { 263 | "vendor": "Samsung", 264 | "model": "SM-T520", 265 | "type": "tablet" 266 | } 267 | }, 268 | { 269 | "desc": "Samsung SmartTV2011", 270 | "ua": "HbbTV/1.1.1 (;;;;;) Maple;2011", 271 | "expect": { 272 | "vendor": "Samsung", 273 | "model": "2011", 274 | "type": "smarttv" 275 | } 276 | }, 277 | { 278 | "desc": "Samsung SmartTV2012", 279 | "ua": "HbbTV/1.1.1 (;Samsung;SmartTV2012;;;) WebKit", 280 | "expect": { 281 | "vendor": "Samsung", 282 | "model": "SmartTV2012", 283 | "type": "smarttv" 284 | } 285 | }, 286 | { 287 | "desc": "Samsung SmartTV2014", 288 | "ua": "HbbTV/1.1.1 (;Samsung;SmartTV2014;T-NT14UDEUC-1060.4;;) WebKit", 289 | "expect": { 290 | "vendor": "Samsung", 291 | "model": "SmartTV2014", 292 | "type": "smarttv" 293 | } 294 | }, 295 | { 296 | "desc": "Samsung SmartTV", 297 | "ua": "Mozilla/5.0 (SMART-TV; Linux; Tizen 2.3) AppleWebkit/538.1 (KHTML, like Gecko) SamsungBrowser/1.0 TV Safari/538.1", 298 | "expect": { 299 | "vendor": "Samsung", 300 | "type": "smarttv" 301 | } 302 | }, 303 | { 304 | "desc": "Sony C5303 (Xperia SP)", 305 | "ua": "Mozilla/5.0 (Linux; Android 4.3; C5303 Build/12.1.A.1.205) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.93 Mobile Safari/537.36", 306 | "expect": { 307 | "vendor": "Sony", 308 | "model": "C5303", 309 | "type": "mobile" 310 | } 311 | }, 312 | { 313 | "desc": "Sony SO-02F (Xperia Z1 F)", 314 | "ua": "Mozilla/5.0 (Linux; Android 4.2.2; SO-02F Build/14.1.H.2.119) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36", 315 | "expect": { 316 | "vendor": "Sony", 317 | "model": "SO-02F", 318 | "type": "mobile" 319 | } 320 | }, 321 | { 322 | "desc": "Sony D6653 (Xperia Z3)", 323 | "ua": "Mozilla/5.0 (Linux; Android 4.4; D6653 Build/23.0.A.0.376) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36", 324 | "expect": { 325 | "vendor": "Sony", 326 | "model": "D6653", 327 | "type": "mobile" 328 | } 329 | }, 330 | { 331 | "desc": "Sony Xperia SOL25 (ZL2)", 332 | "ua": "Mozilla/5.0 (Linux; U; Android 4.4; SOL25 Build/17.1.1.C.1.64) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", 333 | "expect": { 334 | "vendor": "Sony", 335 | "model": "SOL25", 336 | "type": "mobile" 337 | } 338 | }, 339 | { 340 | "desc": "Sony Xperia SP", 341 | "ua": "Mozilla/5.0 (Linux; Android 4.3; C5302 Build/12.1.A.1.201) AppleWebkit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36", 342 | "expect": { 343 | "vendor": "Sony", 344 | "model": "C5302", 345 | "type": "mobile" 346 | } 347 | }, 348 | { 349 | "desc": "Sony SGP521 (Xperia Z2 Tablet)", 350 | "ua": "Mozilla/5.0 (Linux; Android 4.4; SGP521 Build/17.1.A.0.432) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.99 Safari/537.36", 351 | "expect": { 352 | "vendor": "Sony", 353 | "model": "Xperia Tablet", 354 | "type": "tablet" 355 | } 356 | }, 357 | { 358 | "desc": "Sony Tablet S", 359 | "ua": "Mozilla/5.0 (Linux; U; Android 3.1; Sony Tablet S Build/THMAS10000) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13", 360 | "expect": { 361 | "vendor": "Sony", 362 | "model": "Xperia Tablet", 363 | "type": "tablet" 364 | } 365 | }, 366 | { 367 | "desc": "Sony Tablet Z LTE", 368 | "ua": "Mozilla/5.0 (Linux; U; Android 4.1; SonySGP321 Build/10.2.C.0.143) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30", 369 | "expect": { 370 | "vendor": "Sony", 371 | "model": "Xperia Tablet", 372 | "type": "tablet" 373 | } 374 | }, 375 | { 376 | "desc": "Xiaomi 2013023", 377 | "ua": "Mozilla/5.0 (Linux; U; Android 4.2.2; en-US; 2013023 Build/HM2013023) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/10.0.1.512 U3/0.8.0 Mobile Safari/533.1", 378 | "expect": { 379 | "vendor": "Xiaomi", 380 | "model": "2013023", 381 | "type": "mobile" 382 | } 383 | }, 384 | { 385 | "desc": "Xiaomi Hongmi Note 1W", 386 | "ua": "Mozilla/5.0 (Linux; U; Android 4.2.2; zh-CN; HM NOTE 1W Build/JDQ39) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.7.9.439 U3/0.8.0 Mobile Safari/533.1", 387 | "expect": { 388 | "vendor": "Xiaomi", 389 | "model": "HM NOTE 1W", 390 | "type": "mobile" 391 | } 392 | }, 393 | { 394 | "desc": "Xiaomi Mi 3C", 395 | "ua": "Mozilla/5.0 (Linux; U; Android 4.3; zh-CN; MI 3C Build/JLS36C) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/9.7.9.439 U3/0.8.0 Mobile Safari/533.1", 396 | "expect": { 397 | "vendor": "Xiaomi", 398 | "model": "MI 3C", 399 | "type": "mobile" 400 | } 401 | }, 402 | { 403 | "desc": "Xiaomi Mi Note", 404 | "ua": "Mozilla/5.0 (Linux; Android 4.4.4; MI NOTE LTE Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36", 405 | "expect": { 406 | "vendor": "Xiaomi", 407 | "model": "MI NOTE LTE", 408 | "type": "mobile" 409 | } 410 | }, 411 | { 412 | "desc": "Xiaomi Mi One Plus", 413 | "ua": "Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; MI-ONE Plus Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", 414 | "expect": { 415 | "vendor": "Xiaomi", 416 | "model": "MI-ONE Plus", 417 | "type": "mobile" 418 | } 419 | }, 420 | { 421 | "desc": "PlayStation 4", 422 | "ua": "Mozilla/5.0 (PlayStation 4 3.00) AppleWebKit/537.73 (KHTML, like Gecko)", 423 | "expect": { 424 | "vendor": "Sony", 425 | "model": "PlayStation 4", 426 | "type": "console" 427 | } 428 | }, 429 | { 430 | "desc": "Galaxy Nexus", 431 | "ua": "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19", 432 | "expect": { 433 | "vendor": "Samsung", 434 | "model": "Galaxy Nexus", 435 | "type": "mobile" 436 | } 437 | }, 438 | { 439 | "desc": "Samsung Galaxy S5", 440 | "ua": "Mozilla/5.0 (Linux; Android 5.0; SM-G900F Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.78 Mobile Safari/537.36", 441 | "expect": { 442 | "vendor": "Samsung", 443 | "model": "SM-G900F", 444 | "type": "mobile" 445 | } 446 | }, 447 | { 448 | "desc": "Samsung Galaxy S6", 449 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; SM-G920I Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Safari/537.36", 450 | "expect": { 451 | "vendor": "Samsung", 452 | "model": "SM-G920I", 453 | "type": "mobile" 454 | } 455 | }, 456 | { 457 | "desc": "Samsung Galaxy S6 Edge", 458 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; SM-G925I Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.135 Safari/537.36", 459 | "expect": { 460 | "vendor": "Samsung", 461 | "model": "SM-G925I", 462 | "type": "mobile" 463 | } 464 | }, 465 | { 466 | "desc": "Samsung Galaxy Note 5 Chrome", 467 | "ua": "Mozilla/5.0 (Linux; Android 5.1.1; SM-N920C Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.91 Mobile Safari/537.36", 468 | "expect": { 469 | "vendor": "Samsung", 470 | "model": "SM-N920C", 471 | "type": "mobile" 472 | } 473 | }, 474 | { 475 | "desc": "Samsung Galaxy Note 5 Samsung Browser", 476 | "ua": "Mozilla/5.0 (Linux; Android 5.1.1; SAMSUNG SM-N920C Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Mobile Safari/537.36", 477 | "expect": { 478 | "vendor": "Samsung", 479 | "model": "SM-N920C", 480 | "type": "mobile" 481 | } 482 | }, 483 | { 484 | "desc": "Google Chromecast", 485 | "ua": "Mozilla/5.0 (X11; Linux armv7l) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.84 Safari/537.36 CrKey/1.22.79313", 486 | "expect": { 487 | "vendor": "Google", 488 | "model": "Chromecast" 489 | } 490 | }, 491 | { 492 | "desc": "Google Pixel C", 493 | "ua": "Mozilla/5.0 (Linux; Android 7.0; Pixel C Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Safari/537.36", 494 | "expect": { 495 | "vendor": "Google", 496 | "model": "Pixel C", 497 | "type": "tablet" 498 | } 499 | }, 500 | { 501 | "desc": "Google Pixel", 502 | "ua": "Mozilla/5.0 (Linux; Android 7.1; Pixel Build/NDE63V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", 503 | "expect": { 504 | "vendor": "Google", 505 | "model": "Pixel", 506 | "type": "mobile" 507 | } 508 | }, 509 | { 510 | "desc": "Google Pixel", 511 | "ua": "Mozilla/5.0 (Linux; Android 7.1; Pixel XL Build/NDE63X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.85 Mobile Safari/537.36", 512 | "expect": { 513 | "vendor": "Google", 514 | "model": "Pixel XL", 515 | "type": "mobile" 516 | } 517 | }, 518 | 519 | { 520 | "desc": "Generic Android Device", 521 | "ua": "Mozilla/5.0 (Linux; U; Android 6.0.1; i980 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 522 | "expect": { 523 | "vendor": "generic", 524 | "model": "Android 6.0.1" 525 | } 526 | }, 527 | { 528 | "desc": "LG VK Series Tablet", 529 | "ua": "Mozilla/5.0 (Linux; Android 5.0.2; VK700 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.84 Safari/537.36", 530 | "expect": { 531 | "vendor": "LG", 532 | "model": "VK700", 533 | "type": "tablet" 534 | } 535 | }, 536 | { 537 | "desc": "LG LK Series Tablet", 538 | "ua": "Mozilla/5.0 (Linux; Android 5.0.1; LGLK430 Build/LRX21Y) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/38.0.2125.102 Safari/537.36", 539 | "expect": { 540 | "vendor": "LG", 541 | "model": "LK430", 542 | "type": "tablet" 543 | } 544 | }, 545 | { 546 | "desc": "RCA Voyager III Tablet", 547 | "ua": "Mozilla/5.0 (Linux; Android 6.0.1; RCT6973W43 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 548 | "expect": { 549 | "vendor": "RCA", 550 | "model": "RCT6973W43", 551 | "type": "tablet" 552 | } 553 | }, 554 | { 555 | "desc": "RCA Voyager II Tablet", 556 | "ua": "Mozilla/5.0 (Linux; Android 5.0; RCT6773W22B Build/LRX21M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 557 | "expect": { 558 | "vendor": "RCA", 559 | "model": "RCT6773W22B", 560 | "type": "tablet" 561 | } 562 | }, 563 | { 564 | "desc": "Verizon Quanta Tablet", 565 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; QMV7B Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 566 | "expect": { 567 | "vendor": "Verizon", 568 | "model": "QMV7B", 569 | "type": "tablet" 570 | } 571 | }, 572 | { 573 | "desc": "Verizon Ellipsis 8 Tablet", 574 | "ua": "Mozilla/5.0 (Linux; Android 5.1.1; QTAQZ3 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 575 | "expect": { 576 | "vendor": "Verizon", 577 | "model": "QTAQZ3", 578 | "type": "tablet" 579 | } 580 | }, 581 | { 582 | "desc": "Verizon Ellipsis 8HD Tablet", 583 | "ua": "Mozilla/5.0 (Linux; Android 6.0.1; QTASUN1 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.81 Safari/537.36", 584 | "expect": { 585 | "vendor": "Verizon", 586 | "model": "QTASUN1", 587 | "type": "tablet" 588 | } 589 | }, 590 | { 591 | "desc": "Dell Venue 8 Tablet", 592 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; Venue 8 3830 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 593 | "expect": { 594 | "vendor": "Dell", 595 | "model": "Venue 8 3830", 596 | "type": "tablet" 597 | } 598 | }, 599 | { 600 | "desc": "Dell Venue 7 Tablet", 601 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; Venue 7 3730 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 602 | "expect": { 603 | "vendor": "Dell", 604 | "model": "Venue 7 3730", 605 | "type": "tablet" 606 | } 607 | }, 608 | { 609 | "desc": "Barnes & Noble Nook HD+ Tablet", 610 | "ua": "Mozilla/5.0 (Linux; U; Android 4.1.2; en-us; Barnes & Noble Nook HD+ Build/JZO54K; CyanogenMod-10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", 611 | "expect": { 612 | "vendor": "Barnes & Noble", 613 | "model": "Nook HD+", 614 | "type": "tablet" 615 | } 616 | }, 617 | { 618 | "desc": "Barnes & Noble V400 Tablet", 619 | "ua": "Mozilla/5.0 (Linux; Android 4.0.4; BNTV400 Build/IMM76L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.111 Safari/537.36", 620 | "expect": { 621 | "vendor": "Barnes & Noble", 622 | "model": "V400", 623 | "type": "tablet" 624 | } 625 | }, 626 | { 627 | "desc": "NuVision TM101A540N Tablet", 628 | "ua": "Mozilla/5.0 (Linux; Android 5.1; TM101A540N Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/50.0.2661.86 Safari/537.36", 629 | "expect": { 630 | "vendor": "NuVision", 631 | "model": "TM101A540N", 632 | "type": "tablet" 633 | } 634 | }, 635 | { 636 | "desc": "ZTE K Series Tablet", 637 | "ua": "Mozilla/5.0 (Linux; Android 6.0.1; K88 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 638 | "expect": { 639 | "vendor": "ZTE", 640 | "model": "K88", 641 | "type": "tablet" 642 | } 643 | }, 644 | { 645 | "desc": "Swizz GEN610", 646 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; GEN610 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36", 647 | "expect": { 648 | "vendor": "Swiss", 649 | "model": "GEN610", 650 | "type": "mobile" 651 | } 652 | }, 653 | { 654 | "desc": "Swizz ZUR700", 655 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; ZUR700 Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Safari/537.36", 656 | "expect": { 657 | "vendor": "Swiss", 658 | "model": "ZUR700", 659 | "type": "tablet" 660 | } 661 | }, 662 | { 663 | "desc": "Zeki TB782b Tablet", 664 | "ua": "Mozilla/5.0 (Linux; U; Android 4.0.4; en-US; TB782B Build/IMM76D) AppleWebKit/534.31 (KHTML, like Gecko) UCBrowser/9.0.2.299 U3/0.8.0 Mobile Safari/534.31", 665 | "expect": { 666 | "vendor": "Zeki", 667 | "model": "TB782B", 668 | "type": "tablet" 669 | } 670 | }, 671 | { 672 | "desc": "Dragon Touch Tablet", 673 | "ua": "Mozilla/5.0 (Linux; Android 4.0.4; DT9138B Build/IMM76D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36", 674 | "expect": { 675 | "vendor": "Dragon Touch", 676 | "model": "9138B", 677 | "type": "tablet" 678 | } 679 | }, 680 | { 681 | "desc": "Insignia Tablet", 682 | "ua": "Mozilla/5.0 (Linux; U; Android 6.0.1; NS-P08A7100 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/56.0.2924.87 Safari/537.36", 683 | "expect": { 684 | "vendor": "Insignia", 685 | "model": "NS-P08A7100", 686 | "type": "tablet" 687 | } 688 | }, 689 | { 690 | "desc": "Voice Xtreme V75", 691 | "ua": "Mozilla/5.0 (Linux; U; Android 4.2.1; en-us; V75 Build/JOP40D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", 692 | "expect": { 693 | "vendor": "Voice", 694 | "model": "V75", 695 | "type": "mobile" 696 | } 697 | }, 698 | { 699 | "desc": "LvTel V11", 700 | "ua": "Mozilla/5.0 (Linux; Android 5.1.1; V11 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Safari/537.36", 701 | "expect": { 702 | "vendor": "LvTel", 703 | "model": "V11", 704 | "type": "mobile" 705 | } 706 | }, 707 | { 708 | "desc": "Envizen Tablet V100MD", 709 | "ua": "Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; V100MD Build/V100MD.20130816) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30", 710 | "expect": { 711 | "vendor": "Envizen", 712 | "model": "V100MD", 713 | "type": "tablet" 714 | } 715 | }, 716 | { 717 | "desc": "Rotor Tablet", 718 | "ua": "mozilla/5.0 (linux; android 5.0.1; tu_1491 build/lrx22c) applewebkit/537.36 (khtml, like gecko) chrome/43.0.2357.93 safari/537.36", 719 | "expect": { 720 | "vendor": "Rotor", 721 | "model": "1491", 722 | "type": "tablet" 723 | } 724 | }, 725 | { 726 | "desc": "MachSpeed Tablets", 727 | "ua": "Mozilla/5.0 (Linux; Android 4.4.2; Trio 7.85 vQ Build/Trio_7.85_vQ) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36", 728 | "expect": { 729 | "vendor": "MachSpeed", 730 | "model": "Trio 7.85 vQ", 731 | "type": "tablet" 732 | } 733 | }, 734 | { 735 | "desc": "Trinity Tablets", 736 | "ua": "Mozilla/5.0 (Linux; Android 5.0.1; Trinity T101 Build/LRX22C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Safari/537.36", 737 | "expect": { 738 | "vendor": "Trinity", 739 | "model": "T101", 740 | "type": "tablet" 741 | } 742 | }, 743 | { 744 | "desc": "NextBook Next7", 745 | "ua": "Mozilla/5.0 (Linux; U; Android 4.0.4; en-us; Next7P12 Build/IMM76I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30", 746 | "expect": { 747 | "vendor": "NextBook", 748 | "model": "Next7P12", 749 | "type": "tablet" 750 | } 751 | }, 752 | { 753 | "desc": "NextBook Tablets", 754 | "ua": "Mozilla/5.0 (Linux; Android 5.0; NXA8QC116 Build/LRX21V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 755 | "expect": { 756 | "vendor": "NextBook", 757 | "model": "NXA8QC116", 758 | "type": "tablet" 759 | } 760 | }, 761 | { 762 | "desc": "Le Pan Tablets", 763 | "ua": "Mozilla/5.0 (Linux; Android 4.2.2; Le Pan TC802A Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 764 | "expect": { 765 | "vendor": "Le Pan", 766 | "model": "TC802A", 767 | "type": "tablet" 768 | } 769 | }, 770 | { 771 | "desc": "Le Pan Tablets", 772 | "ua": "Mozilla/5.0 (Linux; Android 4.2.2; Le Pan TC802A Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 773 | "expect": { 774 | "vendor": "Le Pan", 775 | "model": "TC802A", 776 | "type": "tablet" 777 | } 778 | }, 779 | { 780 | "desc": "Amazon Kindle Fire Tablet", 781 | "ua": "Mozilla/5.0 (Linux; U; Android 4.4.3; en-us; KFSAWI Build/KTU84M) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.66 like Chrome/39.0.2171.93 Safari/537.36", 782 | "expect": { 783 | "vendor": "Amazon", 784 | "model": "KFSAWI", 785 | "type": "tablet" 786 | } 787 | }, 788 | { 789 | "desc": "Gigaset Tablet", 790 | "ua": "Mozilla/5.0 (Linux; Android 4.2.2; Gigaset QV830 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", 791 | "expect": { 792 | "vendor": "generic", 793 | "model": "Android 4.2.2" 794 | } 795 | }, 796 | { 797 | "desc": "Redmi Note 3", 798 | "ua": "Mozilla/5.0 (Linux; Android 6.0.1; Redmi Note 3 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36", 799 | "expect": { 800 | "vendor": "Xiaomi", 801 | "model": "Redmi Note 3", 802 | "type": "mobile" 803 | } 804 | }, 805 | { 806 | "desc": "MI PAD 2", 807 | "ua": "Mozilla/5.0 (Linux; Android 5.1; MI PAD 2 Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Safari/537.36 [FB_IAB/FB4A;FBAV/137.0.0.24.91;]", 808 | "expect": { 809 | "vendor": "Xiaomi", 810 | "model": "MI PAD 2", 811 | "type": "tablet" 812 | } 813 | } 814 | ] 815 | -------------------------------------------------------------------------------- /Tests/UAParserSwiftTests/engines-test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "desc" : "EdgeHTML", 4 | "ua" : "Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36 Edge/12.0", 5 | "expect" : 6 | { 7 | "name" : "EdgeHTML", 8 | "version" : "12.0" 9 | } 10 | }, 11 | { 12 | "desc" : "Gecko", 13 | "ua" : "Mozilla/5.0 (X11; Linux x86_64; rv:2.0b9pre) Gecko/20110111 Firefox/4.0b9pre", 14 | "expect" : 15 | { 16 | "name" : "Gecko", 17 | "version" : "2.0b9pre" 18 | } 19 | }, 20 | { 21 | "desc" : "KHTML", 22 | "ua" : "Mozilla/5.0 (compatible; Konqueror/4.5; FreeBSD) KHTML/4.5.4 (like Gecko)", 23 | "expect" : 24 | { 25 | "name" : "KHTML", 26 | "version" : "4.5.4" 27 | } 28 | }, 29 | { 30 | "desc" : "NetFront", 31 | "ua" : "Mozilla/4.0 (PDA; Windows CE/1.0.1) NetFront/3.0", 32 | "expect" : 33 | { 34 | "name" : "NetFront", 35 | "version" : "3.0" 36 | } 37 | }, 38 | { 39 | "desc" : "Presto", 40 | "ua" : "Opera/9.80 (Windows NT 6.1; Opera Tablet/15165; U; en) Presto/2.8.149 Version/11.1", 41 | "expect" : 42 | { 43 | "name" : "Presto", 44 | "version" : "2.8.149" 45 | } 46 | }, 47 | { 48 | "desc" : "Tasman", 49 | "ua" : "Mozilla/4.0 (compatible; MSIE 6.0; PPC Mac OS X 10.4.7; Tasman 1.0)", 50 | "expect" : 51 | { 52 | "name" : "Tasman", 53 | "version" : "1.0" 54 | } 55 | }, 56 | { 57 | "desc" : "Trident", 58 | "ua" : "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0)", 59 | "expect" : 60 | { 61 | "name" : "Trident", 62 | "version" : "6.0" 63 | } 64 | }, 65 | { 66 | "desc" : "WebKit", 67 | "ua" : "Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4", 68 | "expect" : 69 | { 70 | "name" : "WebKit", 71 | "version" : "533.19.4" 72 | } 73 | } 74 | ] -------------------------------------------------------------------------------- /Tests/UAParserSwiftTests/os-test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "desc" : "Windows 95", 4 | "ua" : "Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)", 5 | "expect" : 6 | { 7 | "name" : "Windows", 8 | "version" : "95" 9 | } 10 | }, 11 | { 12 | "desc" : "Windows 98", 13 | "ua" : "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)", 14 | "expect" : 15 | { 16 | "name" : "Windows", 17 | "version" : "98" 18 | } 19 | }, 20 | { 21 | "desc" : "Windows ME", 22 | "ua" : "Mozilla/5.0 (Windows; U; Win 9x 4.90) Gecko/20020502 CS 2000 7.0/7.0", 23 | "expect" : 24 | { 25 | "name" : "Windows", 26 | "version" : "ME" 27 | } 28 | }, 29 | { 30 | "desc" : "Windows 2000", 31 | "ua" : "Mozilla/3.0 (compatible; MSIE 3.0; Windows NT 5.0)", 32 | "expect" : 33 | { 34 | "name" : "Windows", 35 | "version" : "2000" 36 | } 37 | }, 38 | { 39 | "desc" : "Windows XP", 40 | "ua" : "Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 5.2)", 41 | "expect" : 42 | { 43 | "name" : "Windows", 44 | "version" : "XP" 45 | } 46 | }, 47 | { 48 | "desc" : "Windows Vista", 49 | "ua" : "Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; fr-FR)", 50 | "expect" : 51 | { 52 | "name" : "Windows", 53 | "version" : "Vista" 54 | } 55 | }, 56 | { 57 | "desc" : "Windows 7", 58 | "ua" : "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)", 59 | "expect" : 60 | { 61 | "name" : "Windows", 62 | "version" : "7" 63 | } 64 | }, 65 | { 66 | "desc" : "Windows 8", 67 | "ua" : "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Win64; x64; Trident/6.0; .NET4.0E; .NET4.0C)", 68 | "expect" : 69 | { 70 | "name" : "Windows", 71 | "version" : "8" 72 | } 73 | }, 74 | { 75 | "desc" : "Windows 10", 76 | "ua" : "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0", 77 | "expect" : 78 | { 79 | "name" : "Windows", 80 | "version" : "10" 81 | } 82 | }, 83 | { 84 | "desc" : "Windows RT", 85 | "ua" : "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0)", 86 | "expect" : 87 | { 88 | "name" : "Windows", 89 | "version" : "RT" 90 | } 91 | }, 92 | { 93 | "desc" : "Windows CE", 94 | "ua" : "Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)", 95 | "expect" : 96 | { 97 | "name" : "Windows", 98 | "version" : "CE" 99 | } 100 | }, 101 | { 102 | "desc" : "Windows Mobile", 103 | "ua" : "Mozilla/5.0 (ZTE-E_N72/N72V1.0.0B02;U;Windows Mobile/6.1;Profile/MIDP-2.0 Configuration/CLDC-1.1;320*240;CTC/2.0) IE/6.0 (compatible; MSIE 4.01; Windows CE; PPC)/UC Browser7.7.1.88", 104 | "expect" : 105 | { 106 | "name" : "Windows Mobile", 107 | "version" : "6.1" 108 | } 109 | }, 110 | { 111 | "desc" : "Windows Phone", 112 | "ua" : "Opera/9.80 (Windows Phone; Opera Mini/7.6.8/35.7518; U; ru) Presto/2.8.119 Version/11.10", 113 | "expect" : 114 | { 115 | "name" : "Windows Phone" 116 | } 117 | }, 118 | { 119 | "desc" : "Windows Phone OS", 120 | "ua" : "Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; DELL; Venue Pro)", 121 | "expect" : 122 | { 123 | "name" : "Windows Phone OS", 124 | "version" : "7.0" 125 | } 126 | }, 127 | { 128 | "desc" : "Windows Phone 8", 129 | "ua" : "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; HTC; Windows Phone 8X by HTC)", 130 | "expect" : 131 | { 132 | "name" : "Windows Phone", 133 | "version" : "8.0" 134 | } 135 | }, 136 | { 137 | "desc" : "BlackBerry", 138 | "ua" : "BlackBerry9300/5.0.0.912 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/378", 139 | "expect" : 140 | { 141 | "name" : "BlackBerry", 142 | "version" : "5.0.0.912" 143 | } 144 | }, 145 | { 146 | "desc" : "BlackBerry 10", 147 | "ua" : "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.3+ (KHTML, like Gecko) Version/10.0.9.386 Mobile Safari/537.3+", 148 | "expect" : 149 | { 150 | "name" : "BlackBerry", 151 | "version" : "10" 152 | } 153 | }, 154 | { 155 | "desc" : "Tizen", 156 | "ua" : "Mozilla/5.0 (Linux; Tizen 2.3; SAMSUNG SM-Z130H) AppleWebKit/537.3 (KHTML, like Gecko) Version/2.3 Mobile Safari/537.3", 157 | "expect" : 158 | { 159 | "name" : "Tizen", 160 | "version" : "2.3" 161 | } 162 | }, 163 | { 164 | "desc" : "Android", 165 | "ua" : "Mozilla/5.0 (Linux; U; Android 2.2.2; en-us; VM670 Build/FRG83G) AppleWebKit/533.1 (KHTML, like Gecko)", 166 | "expect" : 167 | { 168 | "name" : "Android", 169 | "version" : "2.2.2" 170 | } 171 | }, 172 | { 173 | "desc" : "WebOS", 174 | "ua" : "", 175 | "expect" : 176 | { 177 | } 178 | }, 179 | { 180 | "desc" : "Palm OS", 181 | "ua" : "", 182 | "expect" : 183 | { 184 | } 185 | }, 186 | { 187 | "desc" : "QNX", 188 | "ua" : "", 189 | "expect" : 190 | { 191 | } 192 | }, 193 | { 194 | "desc" : "Bada", 195 | "ua" : "", 196 | "expect" : 197 | { 198 | } 199 | }, 200 | { 201 | "desc" : "RIM Tablet OS", 202 | "ua" : "", 203 | "expect" : 204 | { 205 | } 206 | }, 207 | { 208 | "desc" : "MeeGo", 209 | "ua" : "", 210 | "expect" : 211 | { 212 | } 213 | }, 214 | { 215 | "desc" : "Symbian", 216 | "ua" : "", 217 | "expect" : 218 | { 219 | } 220 | }, 221 | { 222 | "desc" : "Firefox OS", 223 | "ua" : "Mozilla/5.0 (Mobile; rv:14.0) Gecko/14.0 Firefox/14.0", 224 | "expect" : 225 | { 226 | "name" : "Firefox OS" 227 | } 228 | }, 229 | { 230 | "desc" : "Nintendo", 231 | "ua" : "", 232 | "expect" : 233 | { 234 | } 235 | }, 236 | { 237 | "desc" : "PlayStation", 238 | "ua" : "", 239 | "expect" : 240 | { 241 | } 242 | }, 243 | { 244 | "desc" : "PlayStation 4", 245 | "ua" : "Mozilla/5.0 (PlayStation 4 3.00) AppleWebKit/537.73 (KHTML, like Gecko)", 246 | "expect" : 247 | { 248 | "name" : "PlayStation", 249 | "version" : "4" 250 | } 251 | }, 252 | { 253 | "desc" : "Mint", 254 | "ua" : "", 255 | "expect" : 256 | { 257 | } 258 | }, 259 | { 260 | "desc" : "Joli", 261 | "ua" : "", 262 | "expect" : 263 | { 264 | } 265 | }, 266 | { 267 | "desc" : "Ubuntu", 268 | "ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.22+ (KHTML, like Gecko) Chromium/17.0.963.56 Chrome/17.0.963.56 Safari/535.22+ Ubuntu/12.04 (3.4.1-0ubuntu1) Epiphany/3.4.1", 269 | "expect" : 270 | { 271 | "name" : "Ubuntu", 272 | "version" : "12.04" 273 | } 274 | }, 275 | { 276 | "desc" : "Ubuntu", 277 | "ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/31.0.1650.63 Chrome/31.0.1650.63 Safari/537.36", 278 | "expect" : 279 | { 280 | "name" : "Ubuntu" 281 | } 282 | }, 283 | { 284 | "desc" : "Debian", 285 | "ua" : "", 286 | "expect" : 287 | { 288 | } 289 | }, 290 | { 291 | "desc" : "OpenSUSE", 292 | "ua" : "", 293 | "expect" : 294 | { 295 | } 296 | }, 297 | { 298 | "desc" : "Gentoo", 299 | "ua" : "", 300 | "expect" : 301 | { 302 | } 303 | }, 304 | { 305 | "desc" : "Arch", 306 | "ua" : "", 307 | "expect" : 308 | { 309 | } 310 | }, 311 | { 312 | "desc" : "Slackware", 313 | "ua" : "", 314 | "expect" : 315 | { 316 | } 317 | }, 318 | { 319 | "desc" : "Fedora", 320 | "ua" : "", 321 | "expect" : 322 | { 323 | } 324 | }, 325 | { 326 | "desc" : "Mandriva", 327 | "ua" : "", 328 | "expect" : 329 | { 330 | } 331 | }, 332 | { 333 | "desc" : "CentOS", 334 | "ua" : "", 335 | "expect" : 336 | { 337 | } 338 | }, 339 | { 340 | "desc" : "PCLinuxOS", 341 | "ua" : "", 342 | "expect" : 343 | { 344 | } 345 | }, 346 | { 347 | "desc" : "RedHat", 348 | "ua" : "", 349 | "expect" : 350 | { 351 | } 352 | }, 353 | { 354 | "desc" : "Zenwalk", 355 | "ua" : "", 356 | "expect" : 357 | { 358 | } 359 | }, 360 | { 361 | "desc" : "Hurd", 362 | "ua" : "", 363 | "expect" : 364 | { 365 | } 366 | }, 367 | { 368 | "desc" : "Linux", 369 | "ua" : "", 370 | "expect" : 371 | { 372 | } 373 | }, 374 | { 375 | "desc" : "GNU", 376 | "ua" : "", 377 | "expect" : 378 | { 379 | } 380 | }, 381 | { 382 | "desc" : "Chromium OS", 383 | "ua" : "", 384 | "expect" : 385 | { 386 | } 387 | }, 388 | { 389 | "desc" : "Solaris", 390 | "ua" : "", 391 | "expect" : 392 | { 393 | } 394 | }, 395 | { 396 | "desc" : "FreeBSD", 397 | "ua" : "", 398 | "expect" : 399 | { 400 | } 401 | }, 402 | { 403 | "desc" : "OpenBSD", 404 | "ua" : "", 405 | "expect" : 406 | { 407 | } 408 | }, 409 | { 410 | "desc" : "NetBSD", 411 | "ua" : "", 412 | "expect" : 413 | { 414 | } 415 | }, 416 | { 417 | "desc" : "DragonFly", 418 | "ua" : "", 419 | "expect" : 420 | { 421 | } 422 | }, 423 | { 424 | "desc" : "iOS in App", 425 | "ua" : "AppName/version CFNetwork/version Darwin/version", 426 | "expect" : 427 | { 428 | "name" : "iOS", 429 | "version" : "cfnetwork/version darwin" 430 | } 431 | }, 432 | { 433 | "desc" : "iOS with Chrome", 434 | "ua" : "Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/7534.48.3", 435 | "expect" : 436 | { 437 | "name" : "iOS", 438 | "version" : "5.1.1" 439 | } 440 | }, 441 | { 442 | "desc" : "iOS with Opera Mini", 443 | "ua" : "Opera/9.80 (iPhone; Opera Mini/7.1.32694/27.1407; U; en) Presto/2.8.119 Version/11.10", 444 | "expect" : 445 | { 446 | "name" : "iOS" 447 | } 448 | }, 449 | { 450 | "desc" : "Mac OS", 451 | "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36", 452 | "expect" : 453 | { 454 | "name" : "Mac OS", 455 | "version" : "10.6.8" 456 | } 457 | }, 458 | { 459 | "desc" : "Haiku", 460 | "ua" : "Mozilla/5.0 (Macintosh; Intel Haiku R1 x86) AppleWebKit/602.1.1 (KHTML, like Gecko) WebPositive/1.2 Version/8.0 Safari/602.1.1", 461 | "expect" : 462 | { 463 | "name" : "Haiku", 464 | "version" : "R1" 465 | } 466 | }, 467 | { 468 | "desc" : "AIX", 469 | "ua" : "", 470 | "expect" : 471 | { 472 | } 473 | }, 474 | { 475 | "desc" : "Plan9", 476 | "ua" : "", 477 | "expect" : 478 | { 479 | } 480 | }, 481 | { 482 | "desc" : "Minix", 483 | "ua" : "", 484 | "expect" : 485 | { 486 | } 487 | }, 488 | { 489 | "desc" : "BeOS", 490 | "ua" : "", 491 | "expect" : 492 | { 493 | } 494 | }, 495 | { 496 | "desc" : "OS/2", 497 | "ua" : "", 498 | "expect" : 499 | { 500 | } 501 | }, 502 | { 503 | "desc" : "AmigaOS", 504 | "ua" : "", 505 | "expect" : 506 | { 507 | } 508 | }, 509 | { 510 | "desc" : "MorphOS", 511 | "ua" : "", 512 | "expect" : 513 | { 514 | } 515 | }, 516 | { 517 | "desc" : "UNIX", 518 | "ua" : "", 519 | "expect" : 520 | { 521 | } 522 | }, 523 | { 524 | "desc" : "iTunes Windows Vista", 525 | "ua" : "iTunes/10.7 (Windows; Microsoft Windows Vista Home Premium Edition Service Pack 1 (Build 6001)) AppleWebKit/536.26.9", 526 | "expect" : 527 | { 528 | "name" : "Windows", 529 | "version" : "Vista" 530 | } 531 | }, 532 | { 533 | "desc" : "iOS BE App", 534 | "ua" : "APP-BE Test/1.0 (iPad; Apple; CPU iPhone OS 7_0_2 like Mac OS X)", 535 | "expect" : 536 | { 537 | "name" : "iOS", 538 | "version" : "7.0.2" 539 | } 540 | }, 541 | { 542 | "desc" : "KTB-Nexus 5", 543 | "ua" : "APP-My App/1.0 (Linux; Android 4.2.1; Nexus 5 Build/JOP40D)", 544 | "expect" : 545 | { 546 | "name" : "Android", 547 | "version" : "4.2.1" 548 | } 549 | } 550 | ] 551 | -------------------------------------------------------------------------------- /UAParserSwift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "UAParserSwift" 3 | s.version = "1.2.1" 4 | s.summary = "User-Agent parser for swift (port of ua-parser-js)" 5 | s.description = <<-DESC 6 | UAParserSwift is a Swift-based library to parse User Agent string; it's a port of ua-parser-js by Faisal Salman created to be mainly used in Swift Server Side applications (but compatible with all Apple's platforms too). 7 | DESC 8 | s.homepage = "https://github.com/malcommac/UAParserSwift.git" 9 | s.license = { :type => "MIT", :file => "LICENSE" } 10 | s.author = { "Daniele Margutti" => "me@danielemargutti.com" } 11 | s.social_media_url = "http://twitter.com/danielemargutti" 12 | s.ios.deployment_target = "11.0" 13 | s.osx.deployment_target = "10.9" 14 | s.watchos.deployment_target = "2.0" 15 | s.tvos.deployment_target = "9.0" 16 | s.source = { :git => "https://github.com/malcommac/UAParserSwift.git", :tag => s.version.to_s } 17 | s.source_files = "Sources/**/*.swift" 18 | s.frameworks = "Foundation" 19 | s.swift_versions = ['5.0', '5.1', '5.3'] 20 | end 21 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 47; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 52D6D9871BEFF229002C0205 /* UAParserSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* UAParserSwift.framework */; }; 11 | 643640B51FACF6CF002C4859 /* cpu-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640B41FACF6CF002C4859 /* cpu-test.json */; }; 12 | 643640B61FACF6CF002C4859 /* cpu-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640B41FACF6CF002C4859 /* cpu-test.json */; }; 13 | 643640B71FACF6CF002C4859 /* cpu-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640B41FACF6CF002C4859 /* cpu-test.json */; }; 14 | 643640BD1FACFB25002C4859 /* engines-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640BC1FACFB25002C4859 /* engines-test.json */; }; 15 | 643640BE1FACFB25002C4859 /* engines-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640BC1FACFB25002C4859 /* engines-test.json */; }; 16 | 643640BF1FACFB25002C4859 /* engines-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640BC1FACFB25002C4859 /* engines-test.json */; }; 17 | 643640C11FACFE28002C4859 /* os-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C01FACFE28002C4859 /* os-test.json */; }; 18 | 643640C21FACFE28002C4859 /* os-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C01FACFE28002C4859 /* os-test.json */; }; 19 | 643640C31FACFE28002C4859 /* os-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C01FACFE28002C4859 /* os-test.json */; }; 20 | 643640C51FADBDFC002C4859 /* device-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C41FADBDFC002C4859 /* device-test.json */; }; 21 | 643640C61FADBDFC002C4859 /* device-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C41FADBDFC002C4859 /* device-test.json */; }; 22 | 643640C71FADBDFC002C4859 /* device-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C41FADBDFC002C4859 /* device-test.json */; }; 23 | 643640C91FADE74A002C4859 /* browser-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C81FADE74A002C4859 /* browser-test.json */; }; 24 | 643640CA1FADE74A002C4859 /* browser-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C81FADE74A002C4859 /* browser-test.json */; }; 25 | 643640CB1FADE74A002C4859 /* browser-test.json in Resources */ = {isa = PBXBuildFile; fileRef = 643640C81FADE74A002C4859 /* browser-test.json */; }; 26 | 64C2F9FF1FAF849C00E3EEDC /* UAParserSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C2F9FE1FAF849C00E3EEDC /* UAParserSwift.swift */; }; 27 | 64C2FA001FAF849C00E3EEDC /* UAParserSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C2F9FE1FAF849C00E3EEDC /* UAParserSwift.swift */; }; 28 | 64C2FA011FAF849C00E3EEDC /* UAParserSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C2F9FE1FAF849C00E3EEDC /* UAParserSwift.swift */; }; 29 | 64C2FA021FAF849C00E3EEDC /* UAParserSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C2F9FE1FAF849C00E3EEDC /* UAParserSwift.swift */; }; 30 | 64CD6C331FAA2175009B4F9A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64CD6C321FAA2175009B4F9A /* AppDelegate.swift */; }; 31 | 64CD6C351FAA2175009B4F9A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64CD6C341FAA2175009B4F9A /* ViewController.swift */; }; 32 | 64CD6C381FAA2175009B4F9A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64CD6C361FAA2175009B4F9A /* Main.storyboard */; }; 33 | 64CD6C3A1FAA2175009B4F9A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 64CD6C391FAA2175009B4F9A /* Assets.xcassets */; }; 34 | 64CD6C3D1FAA2175009B4F9A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64CD6C3B1FAA2175009B4F9A /* LaunchScreen.storyboard */; }; 35 | 64CD6C451FAA2181009B4F9A /* UAParserSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* UAParserSwift.framework */; }; 36 | 64CD6C471FAA218E009B4F9A /* UAParserSwift.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* UAParserSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 37 | 8933C78E1EB5B82C000D00A4 /* UAParserSwift_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7891EB5B82A000D00A4 /* UAParserSwift_Tests.swift */; }; 38 | 8933C78F1EB5B82C000D00A4 /* UAParserSwift_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7891EB5B82A000D00A4 /* UAParserSwift_Tests.swift */; }; 39 | 8933C7901EB5B82D000D00A4 /* UAParserSwift_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7891EB5B82A000D00A4 /* UAParserSwift_Tests.swift */; }; 40 | DD7502881C68FEDE006590AF /* UAParserSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6DA0F1BF000BD002C0205 /* UAParserSwift.framework */; }; 41 | DD7502921C690C7A006590AF /* UAParserSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D9F01BEFFFBE002C0205 /* UAParserSwift.framework */; }; 42 | /* End PBXBuildFile section */ 43 | 44 | /* Begin PBXContainerItemProxy section */ 45 | 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 48 | proxyType = 1; 49 | remoteGlobalIDString = 52D6D97B1BEFF229002C0205; 50 | remoteInfo = UAParserSwift; 51 | }; 52 | 64CD6C421FAA217B009B4F9A /* PBXContainerItemProxy */ = { 53 | isa = PBXContainerItemProxy; 54 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 55 | proxyType = 1; 56 | remoteGlobalIDString = 52D6D97B1BEFF229002C0205; 57 | remoteInfo = "UAParserSwift-iOS"; 58 | }; 59 | DD7502801C68FCFC006590AF /* PBXContainerItemProxy */ = { 60 | isa = PBXContainerItemProxy; 61 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 62 | proxyType = 1; 63 | remoteGlobalIDString = 52D6DA0E1BF000BD002C0205; 64 | remoteInfo = "UAParserSwift-macOS"; 65 | }; 66 | DD7502931C690C7A006590AF /* PBXContainerItemProxy */ = { 67 | isa = PBXContainerItemProxy; 68 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 69 | proxyType = 1; 70 | remoteGlobalIDString = 52D6D9EF1BEFFFBE002C0205; 71 | remoteInfo = "UAParserSwift-tvOS"; 72 | }; 73 | /* End PBXContainerItemProxy section */ 74 | 75 | /* Begin PBXCopyFilesBuildPhase section */ 76 | 64CD6C461FAA2183009B4F9A /* Copy Frameworks */ = { 77 | isa = PBXCopyFilesBuildPhase; 78 | buildActionMask = 2147483647; 79 | dstPath = ""; 80 | dstSubfolderSpec = 10; 81 | files = ( 82 | 64CD6C471FAA218E009B4F9A /* UAParserSwift.framework in Copy Frameworks */, 83 | ); 84 | name = "Copy Frameworks"; 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXCopyFilesBuildPhase section */ 88 | 89 | /* Begin PBXFileReference section */ 90 | 52D6D97C1BEFF229002C0205 /* UAParserSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UAParserSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 91 | 52D6D9861BEFF229002C0205 /* UAParserSwift-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UAParserSwift-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 92 | 52D6D9E21BEFFF6E002C0205 /* UAParserSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UAParserSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 93 | 52D6D9F01BEFFFBE002C0205 /* UAParserSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UAParserSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 94 | 52D6DA0F1BF000BD002C0205 /* UAParserSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UAParserSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 95 | 643640B41FACF6CF002C4859 /* cpu-test.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "cpu-test.json"; sourceTree = ""; }; 96 | 643640BC1FACFB25002C4859 /* engines-test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "engines-test.json"; sourceTree = ""; }; 97 | 643640C01FACFE28002C4859 /* os-test.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "os-test.json"; sourceTree = ""; }; 98 | 643640C41FADBDFC002C4859 /* device-test.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "device-test.json"; sourceTree = ""; }; 99 | 643640C81FADE74A002C4859 /* browser-test.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "browser-test.json"; sourceTree = ""; }; 100 | 64C2F9FE1FAF849C00E3EEDC /* UAParserSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UAParserSwift.swift; path = UAParserSwift/UAParserSwift.swift; sourceTree = ""; }; 101 | 64CD6C301FAA2175009B4F9A /* TestApplication.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestApplication.app; sourceTree = BUILT_PRODUCTS_DIR; }; 102 | 64CD6C321FAA2175009B4F9A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 103 | 64CD6C341FAA2175009B4F9A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 104 | 64CD6C371FAA2175009B4F9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 105 | 64CD6C391FAA2175009B4F9A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 106 | 64CD6C3C1FAA2175009B4F9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 107 | 64CD6C3E1FAA2175009B4F9A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 108 | 8933C7891EB5B82A000D00A4 /* UAParserSwift_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UAParserSwift_Tests.swift; sourceTree = ""; }; 109 | AD2FAA261CD0B6D800659CF4 /* UAParserSwift.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = UAParserSwift.plist; sourceTree = ""; }; 110 | AD2FAA281CD0B6E100659CF4 /* UAParserSwiftTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = UAParserSwiftTests.plist; sourceTree = ""; }; 111 | DD75027A1C68FCFC006590AF /* UAParserSwift-macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UAParserSwift-macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 112 | DD75028D1C690C7A006590AF /* UAParserSwift-tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UAParserSwift-tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 113 | /* End PBXFileReference section */ 114 | 115 | /* Begin PBXFrameworksBuildPhase section */ 116 | 52D6D9781BEFF229002C0205 /* Frameworks */ = { 117 | isa = PBXFrameworksBuildPhase; 118 | buildActionMask = 2147483647; 119 | files = ( 120 | ); 121 | runOnlyForDeploymentPostprocessing = 0; 122 | }; 123 | 52D6D9831BEFF229002C0205 /* Frameworks */ = { 124 | isa = PBXFrameworksBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | 52D6D9871BEFF229002C0205 /* UAParserSwift.framework in Frameworks */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */ = { 132 | isa = PBXFrameworksBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */ = { 139 | isa = PBXFrameworksBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | 52D6DA0B1BF000BD002C0205 /* Frameworks */ = { 146 | isa = PBXFrameworksBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | ); 150 | runOnlyForDeploymentPostprocessing = 0; 151 | }; 152 | 64CD6C2D1FAA2175009B4F9A /* Frameworks */ = { 153 | isa = PBXFrameworksBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | 64CD6C451FAA2181009B4F9A /* UAParserSwift.framework in Frameworks */, 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | DD7502771C68FCFC006590AF /* Frameworks */ = { 161 | isa = PBXFrameworksBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | DD7502881C68FEDE006590AF /* UAParserSwift.framework in Frameworks */, 165 | ); 166 | runOnlyForDeploymentPostprocessing = 0; 167 | }; 168 | DD75028A1C690C7A006590AF /* Frameworks */ = { 169 | isa = PBXFrameworksBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | DD7502921C690C7A006590AF /* UAParserSwift.framework in Frameworks */, 173 | ); 174 | runOnlyForDeploymentPostprocessing = 0; 175 | }; 176 | /* End PBXFrameworksBuildPhase section */ 177 | 178 | /* Begin PBXGroup section */ 179 | 52D6D9721BEFF229002C0205 = { 180 | isa = PBXGroup; 181 | children = ( 182 | 8933C7811EB5B7E0000D00A4 /* Sources */, 183 | 8933C7831EB5B7EB000D00A4 /* Tests */, 184 | 52D6D99C1BEFF38C002C0205 /* Configs */, 185 | 64CD6C311FAA2175009B4F9A /* TestApplication */, 186 | 52D6D97D1BEFF229002C0205 /* Products */, 187 | 64CD6C441FAA2181009B4F9A /* Frameworks */, 188 | ); 189 | sourceTree = ""; 190 | }; 191 | 52D6D97D1BEFF229002C0205 /* Products */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 52D6D97C1BEFF229002C0205 /* UAParserSwift.framework */, 195 | 52D6D9861BEFF229002C0205 /* UAParserSwift-iOS Tests.xctest */, 196 | 52D6D9E21BEFFF6E002C0205 /* UAParserSwift.framework */, 197 | 52D6D9F01BEFFFBE002C0205 /* UAParserSwift.framework */, 198 | 52D6DA0F1BF000BD002C0205 /* UAParserSwift.framework */, 199 | DD75027A1C68FCFC006590AF /* UAParserSwift-macOS Tests.xctest */, 200 | DD75028D1C690C7A006590AF /* UAParserSwift-tvOS Tests.xctest */, 201 | 64CD6C301FAA2175009B4F9A /* TestApplication.app */, 202 | ); 203 | name = Products; 204 | sourceTree = ""; 205 | }; 206 | 52D6D99C1BEFF38C002C0205 /* Configs */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | DD7502721C68FC1B006590AF /* Frameworks */, 210 | DD7502731C68FC20006590AF /* Tests */, 211 | ); 212 | path = Configs; 213 | sourceTree = ""; 214 | }; 215 | 64CD6C311FAA2175009B4F9A /* TestApplication */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | 64CD6C321FAA2175009B4F9A /* AppDelegate.swift */, 219 | 64CD6C341FAA2175009B4F9A /* ViewController.swift */, 220 | 64CD6C361FAA2175009B4F9A /* Main.storyboard */, 221 | 64CD6C391FAA2175009B4F9A /* Assets.xcassets */, 222 | 64CD6C3B1FAA2175009B4F9A /* LaunchScreen.storyboard */, 223 | 64CD6C3E1FAA2175009B4F9A /* Info.plist */, 224 | ); 225 | path = TestApplication; 226 | sourceTree = ""; 227 | }; 228 | 64CD6C441FAA2181009B4F9A /* Frameworks */ = { 229 | isa = PBXGroup; 230 | children = ( 231 | ); 232 | name = Frameworks; 233 | sourceTree = ""; 234 | }; 235 | 8933C7811EB5B7E0000D00A4 /* Sources */ = { 236 | isa = PBXGroup; 237 | children = ( 238 | 64C2F9FE1FAF849C00E3EEDC /* UAParserSwift.swift */, 239 | ); 240 | path = Sources; 241 | sourceTree = ""; 242 | }; 243 | 8933C7831EB5B7EB000D00A4 /* Tests */ = { 244 | isa = PBXGroup; 245 | children = ( 246 | 8933C7891EB5B82A000D00A4 /* UAParserSwift_Tests.swift */, 247 | 643640B41FACF6CF002C4859 /* cpu-test.json */, 248 | 643640BC1FACFB25002C4859 /* engines-test.json */, 249 | 643640C01FACFE28002C4859 /* os-test.json */, 250 | 643640C41FADBDFC002C4859 /* device-test.json */, 251 | 643640C81FADE74A002C4859 /* browser-test.json */, 252 | ); 253 | name = Tests; 254 | path = Tests/UAParserSwiftTests; 255 | sourceTree = ""; 256 | }; 257 | DD7502721C68FC1B006590AF /* Frameworks */ = { 258 | isa = PBXGroup; 259 | children = ( 260 | AD2FAA261CD0B6D800659CF4 /* UAParserSwift.plist */, 261 | ); 262 | name = Frameworks; 263 | sourceTree = ""; 264 | }; 265 | DD7502731C68FC20006590AF /* Tests */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | AD2FAA281CD0B6E100659CF4 /* UAParserSwiftTests.plist */, 269 | ); 270 | name = Tests; 271 | sourceTree = ""; 272 | }; 273 | /* End PBXGroup section */ 274 | 275 | /* Begin PBXHeadersBuildPhase section */ 276 | 52D6D9791BEFF229002C0205 /* Headers */ = { 277 | isa = PBXHeadersBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | 52D6D9DF1BEFFF6E002C0205 /* Headers */ = { 284 | isa = PBXHeadersBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | 52D6D9ED1BEFFFBE002C0205 /* Headers */ = { 291 | isa = PBXHeadersBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | 52D6DA0C1BF000BD002C0205 /* Headers */ = { 298 | isa = PBXHeadersBuildPhase; 299 | buildActionMask = 2147483647; 300 | files = ( 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | /* End PBXHeadersBuildPhase section */ 305 | 306 | /* Begin PBXNativeTarget section */ 307 | 52D6D97B1BEFF229002C0205 /* UAParserSwift-iOS */ = { 308 | isa = PBXNativeTarget; 309 | buildConfigurationList = 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-iOS" */; 310 | buildPhases = ( 311 | 52D6D9771BEFF229002C0205 /* Sources */, 312 | 52D6D9781BEFF229002C0205 /* Frameworks */, 313 | 52D6D9791BEFF229002C0205 /* Headers */, 314 | 52D6D97A1BEFF229002C0205 /* Resources */, 315 | ); 316 | buildRules = ( 317 | ); 318 | dependencies = ( 319 | ); 320 | name = "UAParserSwift-iOS"; 321 | productName = UAParserSwift; 322 | productReference = 52D6D97C1BEFF229002C0205 /* UAParserSwift.framework */; 323 | productType = "com.apple.product-type.framework"; 324 | }; 325 | 52D6D9851BEFF229002C0205 /* UAParserSwift-iOS Tests */ = { 326 | isa = PBXNativeTarget; 327 | buildConfigurationList = 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-iOS Tests" */; 328 | buildPhases = ( 329 | 52D6D9821BEFF229002C0205 /* Sources */, 330 | 52D6D9831BEFF229002C0205 /* Frameworks */, 331 | 52D6D9841BEFF229002C0205 /* Resources */, 332 | ); 333 | buildRules = ( 334 | ); 335 | dependencies = ( 336 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */, 337 | ); 338 | name = "UAParserSwift-iOS Tests"; 339 | productName = UAParserSwiftTests; 340 | productReference = 52D6D9861BEFF229002C0205 /* UAParserSwift-iOS Tests.xctest */; 341 | productType = "com.apple.product-type.bundle.unit-test"; 342 | }; 343 | 52D6D9E11BEFFF6E002C0205 /* UAParserSwift-watchOS */ = { 344 | isa = PBXNativeTarget; 345 | buildConfigurationList = 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-watchOS" */; 346 | buildPhases = ( 347 | 52D6D9DD1BEFFF6E002C0205 /* Sources */, 348 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */, 349 | 52D6D9DF1BEFFF6E002C0205 /* Headers */, 350 | 52D6D9E01BEFFF6E002C0205 /* Resources */, 351 | ); 352 | buildRules = ( 353 | ); 354 | dependencies = ( 355 | ); 356 | name = "UAParserSwift-watchOS"; 357 | productName = "UAParserSwift-watchOS"; 358 | productReference = 52D6D9E21BEFFF6E002C0205 /* UAParserSwift.framework */; 359 | productType = "com.apple.product-type.framework"; 360 | }; 361 | 52D6D9EF1BEFFFBE002C0205 /* UAParserSwift-tvOS */ = { 362 | isa = PBXNativeTarget; 363 | buildConfigurationList = 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-tvOS" */; 364 | buildPhases = ( 365 | 52D6D9EB1BEFFFBE002C0205 /* Sources */, 366 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */, 367 | 52D6D9ED1BEFFFBE002C0205 /* Headers */, 368 | 52D6D9EE1BEFFFBE002C0205 /* Resources */, 369 | ); 370 | buildRules = ( 371 | ); 372 | dependencies = ( 373 | ); 374 | name = "UAParserSwift-tvOS"; 375 | productName = "UAParserSwift-tvOS"; 376 | productReference = 52D6D9F01BEFFFBE002C0205 /* UAParserSwift.framework */; 377 | productType = "com.apple.product-type.framework"; 378 | }; 379 | 52D6DA0E1BF000BD002C0205 /* UAParserSwift-macOS */ = { 380 | isa = PBXNativeTarget; 381 | buildConfigurationList = 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-macOS" */; 382 | buildPhases = ( 383 | 52D6DA0A1BF000BD002C0205 /* Sources */, 384 | 52D6DA0B1BF000BD002C0205 /* Frameworks */, 385 | 52D6DA0C1BF000BD002C0205 /* Headers */, 386 | 52D6DA0D1BF000BD002C0205 /* Resources */, 387 | ); 388 | buildRules = ( 389 | ); 390 | dependencies = ( 391 | ); 392 | name = "UAParserSwift-macOS"; 393 | productName = "UAParserSwift-macOS"; 394 | productReference = 52D6DA0F1BF000BD002C0205 /* UAParserSwift.framework */; 395 | productType = "com.apple.product-type.framework"; 396 | }; 397 | 64CD6C2F1FAA2175009B4F9A /* TestApplication */ = { 398 | isa = PBXNativeTarget; 399 | buildConfigurationList = 64CD6C411FAA2175009B4F9A /* Build configuration list for PBXNativeTarget "TestApplication" */; 400 | buildPhases = ( 401 | 64CD6C2C1FAA2175009B4F9A /* Sources */, 402 | 64CD6C2D1FAA2175009B4F9A /* Frameworks */, 403 | 64CD6C2E1FAA2175009B4F9A /* Resources */, 404 | 64CD6C461FAA2183009B4F9A /* Copy Frameworks */, 405 | ); 406 | buildRules = ( 407 | ); 408 | dependencies = ( 409 | 64CD6C431FAA217B009B4F9A /* PBXTargetDependency */, 410 | ); 411 | name = TestApplication; 412 | productName = TestApplication; 413 | productReference = 64CD6C301FAA2175009B4F9A /* TestApplication.app */; 414 | productType = "com.apple.product-type.application"; 415 | }; 416 | DD7502791C68FCFC006590AF /* UAParserSwift-macOS Tests */ = { 417 | isa = PBXNativeTarget; 418 | buildConfigurationList = DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "UAParserSwift-macOS Tests" */; 419 | buildPhases = ( 420 | DD7502761C68FCFC006590AF /* Sources */, 421 | DD7502771C68FCFC006590AF /* Frameworks */, 422 | DD7502781C68FCFC006590AF /* Resources */, 423 | ); 424 | buildRules = ( 425 | ); 426 | dependencies = ( 427 | DD7502811C68FCFC006590AF /* PBXTargetDependency */, 428 | ); 429 | name = "UAParserSwift-macOS Tests"; 430 | productName = "UAParserSwift-OS Tests"; 431 | productReference = DD75027A1C68FCFC006590AF /* UAParserSwift-macOS Tests.xctest */; 432 | productType = "com.apple.product-type.bundle.unit-test"; 433 | }; 434 | DD75028C1C690C7A006590AF /* UAParserSwift-tvOS Tests */ = { 435 | isa = PBXNativeTarget; 436 | buildConfigurationList = DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "UAParserSwift-tvOS Tests" */; 437 | buildPhases = ( 438 | DD7502891C690C7A006590AF /* Sources */, 439 | DD75028A1C690C7A006590AF /* Frameworks */, 440 | DD75028B1C690C7A006590AF /* Resources */, 441 | ); 442 | buildRules = ( 443 | ); 444 | dependencies = ( 445 | DD7502941C690C7A006590AF /* PBXTargetDependency */, 446 | ); 447 | name = "UAParserSwift-tvOS Tests"; 448 | productName = "UAParserSwift-tvOS Tests"; 449 | productReference = DD75028D1C690C7A006590AF /* UAParserSwift-tvOS Tests.xctest */; 450 | productType = "com.apple.product-type.bundle.unit-test"; 451 | }; 452 | /* End PBXNativeTarget section */ 453 | 454 | /* Begin PBXProject section */ 455 | 52D6D9731BEFF229002C0205 /* Project object */ = { 456 | isa = PBXProject; 457 | attributes = { 458 | LastSwiftUpdateCheck = 0910; 459 | LastUpgradeCheck = 1220; 460 | ORGANIZATIONNAME = UAParserSwift; 461 | TargetAttributes = { 462 | 52D6D97B1BEFF229002C0205 = { 463 | CreatedOnToolsVersion = 7.1; 464 | LastSwiftMigration = 1220; 465 | }; 466 | 52D6D9851BEFF229002C0205 = { 467 | CreatedOnToolsVersion = 7.1; 468 | LastSwiftMigration = 0800; 469 | }; 470 | 52D6D9E11BEFFF6E002C0205 = { 471 | CreatedOnToolsVersion = 7.1; 472 | LastSwiftMigration = 0910; 473 | }; 474 | 52D6D9EF1BEFFFBE002C0205 = { 475 | CreatedOnToolsVersion = 7.1; 476 | LastSwiftMigration = 0910; 477 | }; 478 | 52D6DA0E1BF000BD002C0205 = { 479 | CreatedOnToolsVersion = 7.1; 480 | LastSwiftMigration = 0910; 481 | }; 482 | 64CD6C2F1FAA2175009B4F9A = { 483 | CreatedOnToolsVersion = 9.1; 484 | LastSwiftMigration = 1220; 485 | ProvisioningStyle = Automatic; 486 | }; 487 | DD7502791C68FCFC006590AF = { 488 | CreatedOnToolsVersion = 7.2.1; 489 | LastSwiftMigration = 0800; 490 | }; 491 | DD75028C1C690C7A006590AF = { 492 | CreatedOnToolsVersion = 7.2.1; 493 | LastSwiftMigration = 0800; 494 | }; 495 | }; 496 | }; 497 | buildConfigurationList = 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "UAParserSwift" */; 498 | compatibilityVersion = "Xcode 6.3"; 499 | developmentRegion = en; 500 | hasScannedForEncodings = 0; 501 | knownRegions = ( 502 | en, 503 | Base, 504 | ); 505 | mainGroup = 52D6D9721BEFF229002C0205; 506 | productRefGroup = 52D6D97D1BEFF229002C0205 /* Products */; 507 | projectDirPath = ""; 508 | projectRoot = ""; 509 | targets = ( 510 | 52D6D97B1BEFF229002C0205 /* UAParserSwift-iOS */, 511 | 52D6DA0E1BF000BD002C0205 /* UAParserSwift-macOS */, 512 | 52D6D9E11BEFFF6E002C0205 /* UAParserSwift-watchOS */, 513 | 52D6D9EF1BEFFFBE002C0205 /* UAParserSwift-tvOS */, 514 | 52D6D9851BEFF229002C0205 /* UAParserSwift-iOS Tests */, 515 | DD7502791C68FCFC006590AF /* UAParserSwift-macOS Tests */, 516 | DD75028C1C690C7A006590AF /* UAParserSwift-tvOS Tests */, 517 | 64CD6C2F1FAA2175009B4F9A /* TestApplication */, 518 | ); 519 | }; 520 | /* End PBXProject section */ 521 | 522 | /* Begin PBXResourcesBuildPhase section */ 523 | 52D6D97A1BEFF229002C0205 /* Resources */ = { 524 | isa = PBXResourcesBuildPhase; 525 | buildActionMask = 2147483647; 526 | files = ( 527 | ); 528 | runOnlyForDeploymentPostprocessing = 0; 529 | }; 530 | 52D6D9841BEFF229002C0205 /* Resources */ = { 531 | isa = PBXResourcesBuildPhase; 532 | buildActionMask = 2147483647; 533 | files = ( 534 | 643640C51FADBDFC002C4859 /* device-test.json in Resources */, 535 | 643640B51FACF6CF002C4859 /* cpu-test.json in Resources */, 536 | 643640BD1FACFB25002C4859 /* engines-test.json in Resources */, 537 | 643640C11FACFE28002C4859 /* os-test.json in Resources */, 538 | 643640C91FADE74A002C4859 /* browser-test.json in Resources */, 539 | ); 540 | runOnlyForDeploymentPostprocessing = 0; 541 | }; 542 | 52D6D9E01BEFFF6E002C0205 /* Resources */ = { 543 | isa = PBXResourcesBuildPhase; 544 | buildActionMask = 2147483647; 545 | files = ( 546 | ); 547 | runOnlyForDeploymentPostprocessing = 0; 548 | }; 549 | 52D6D9EE1BEFFFBE002C0205 /* Resources */ = { 550 | isa = PBXResourcesBuildPhase; 551 | buildActionMask = 2147483647; 552 | files = ( 553 | ); 554 | runOnlyForDeploymentPostprocessing = 0; 555 | }; 556 | 52D6DA0D1BF000BD002C0205 /* Resources */ = { 557 | isa = PBXResourcesBuildPhase; 558 | buildActionMask = 2147483647; 559 | files = ( 560 | ); 561 | runOnlyForDeploymentPostprocessing = 0; 562 | }; 563 | 64CD6C2E1FAA2175009B4F9A /* Resources */ = { 564 | isa = PBXResourcesBuildPhase; 565 | buildActionMask = 2147483647; 566 | files = ( 567 | 64CD6C3D1FAA2175009B4F9A /* LaunchScreen.storyboard in Resources */, 568 | 64CD6C3A1FAA2175009B4F9A /* Assets.xcassets in Resources */, 569 | 64CD6C381FAA2175009B4F9A /* Main.storyboard in Resources */, 570 | ); 571 | runOnlyForDeploymentPostprocessing = 0; 572 | }; 573 | DD7502781C68FCFC006590AF /* Resources */ = { 574 | isa = PBXResourcesBuildPhase; 575 | buildActionMask = 2147483647; 576 | files = ( 577 | 643640C61FADBDFC002C4859 /* device-test.json in Resources */, 578 | 643640B61FACF6CF002C4859 /* cpu-test.json in Resources */, 579 | 643640BE1FACFB25002C4859 /* engines-test.json in Resources */, 580 | 643640C21FACFE28002C4859 /* os-test.json in Resources */, 581 | 643640CA1FADE74A002C4859 /* browser-test.json in Resources */, 582 | ); 583 | runOnlyForDeploymentPostprocessing = 0; 584 | }; 585 | DD75028B1C690C7A006590AF /* Resources */ = { 586 | isa = PBXResourcesBuildPhase; 587 | buildActionMask = 2147483647; 588 | files = ( 589 | 643640C71FADBDFC002C4859 /* device-test.json in Resources */, 590 | 643640B71FACF6CF002C4859 /* cpu-test.json in Resources */, 591 | 643640BF1FACFB25002C4859 /* engines-test.json in Resources */, 592 | 643640C31FACFE28002C4859 /* os-test.json in Resources */, 593 | 643640CB1FADE74A002C4859 /* browser-test.json in Resources */, 594 | ); 595 | runOnlyForDeploymentPostprocessing = 0; 596 | }; 597 | /* End PBXResourcesBuildPhase section */ 598 | 599 | /* Begin PBXSourcesBuildPhase section */ 600 | 52D6D9771BEFF229002C0205 /* Sources */ = { 601 | isa = PBXSourcesBuildPhase; 602 | buildActionMask = 2147483647; 603 | files = ( 604 | 64C2F9FF1FAF849C00E3EEDC /* UAParserSwift.swift in Sources */, 605 | ); 606 | runOnlyForDeploymentPostprocessing = 0; 607 | }; 608 | 52D6D9821BEFF229002C0205 /* Sources */ = { 609 | isa = PBXSourcesBuildPhase; 610 | buildActionMask = 2147483647; 611 | files = ( 612 | 8933C7901EB5B82D000D00A4 /* UAParserSwift_Tests.swift in Sources */, 613 | ); 614 | runOnlyForDeploymentPostprocessing = 0; 615 | }; 616 | 52D6D9DD1BEFFF6E002C0205 /* Sources */ = { 617 | isa = PBXSourcesBuildPhase; 618 | buildActionMask = 2147483647; 619 | files = ( 620 | 64C2FA011FAF849C00E3EEDC /* UAParserSwift.swift in Sources */, 621 | ); 622 | runOnlyForDeploymentPostprocessing = 0; 623 | }; 624 | 52D6D9EB1BEFFFBE002C0205 /* Sources */ = { 625 | isa = PBXSourcesBuildPhase; 626 | buildActionMask = 2147483647; 627 | files = ( 628 | 64C2FA021FAF849C00E3EEDC /* UAParserSwift.swift in Sources */, 629 | ); 630 | runOnlyForDeploymentPostprocessing = 0; 631 | }; 632 | 52D6DA0A1BF000BD002C0205 /* Sources */ = { 633 | isa = PBXSourcesBuildPhase; 634 | buildActionMask = 2147483647; 635 | files = ( 636 | 64C2FA001FAF849C00E3EEDC /* UAParserSwift.swift in Sources */, 637 | ); 638 | runOnlyForDeploymentPostprocessing = 0; 639 | }; 640 | 64CD6C2C1FAA2175009B4F9A /* Sources */ = { 641 | isa = PBXSourcesBuildPhase; 642 | buildActionMask = 2147483647; 643 | files = ( 644 | 64CD6C351FAA2175009B4F9A /* ViewController.swift in Sources */, 645 | 64CD6C331FAA2175009B4F9A /* AppDelegate.swift in Sources */, 646 | ); 647 | runOnlyForDeploymentPostprocessing = 0; 648 | }; 649 | DD7502761C68FCFC006590AF /* Sources */ = { 650 | isa = PBXSourcesBuildPhase; 651 | buildActionMask = 2147483647; 652 | files = ( 653 | 8933C78F1EB5B82C000D00A4 /* UAParserSwift_Tests.swift in Sources */, 654 | ); 655 | runOnlyForDeploymentPostprocessing = 0; 656 | }; 657 | DD7502891C690C7A006590AF /* Sources */ = { 658 | isa = PBXSourcesBuildPhase; 659 | buildActionMask = 2147483647; 660 | files = ( 661 | 8933C78E1EB5B82C000D00A4 /* UAParserSwift_Tests.swift in Sources */, 662 | ); 663 | runOnlyForDeploymentPostprocessing = 0; 664 | }; 665 | /* End PBXSourcesBuildPhase section */ 666 | 667 | /* Begin PBXTargetDependency section */ 668 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */ = { 669 | isa = PBXTargetDependency; 670 | target = 52D6D97B1BEFF229002C0205 /* UAParserSwift-iOS */; 671 | targetProxy = 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */; 672 | }; 673 | 64CD6C431FAA217B009B4F9A /* PBXTargetDependency */ = { 674 | isa = PBXTargetDependency; 675 | target = 52D6D97B1BEFF229002C0205 /* UAParserSwift-iOS */; 676 | targetProxy = 64CD6C421FAA217B009B4F9A /* PBXContainerItemProxy */; 677 | }; 678 | DD7502811C68FCFC006590AF /* PBXTargetDependency */ = { 679 | isa = PBXTargetDependency; 680 | target = 52D6DA0E1BF000BD002C0205 /* UAParserSwift-macOS */; 681 | targetProxy = DD7502801C68FCFC006590AF /* PBXContainerItemProxy */; 682 | }; 683 | DD7502941C690C7A006590AF /* PBXTargetDependency */ = { 684 | isa = PBXTargetDependency; 685 | target = 52D6D9EF1BEFFFBE002C0205 /* UAParserSwift-tvOS */; 686 | targetProxy = DD7502931C690C7A006590AF /* PBXContainerItemProxy */; 687 | }; 688 | /* End PBXTargetDependency section */ 689 | 690 | /* Begin PBXVariantGroup section */ 691 | 64CD6C361FAA2175009B4F9A /* Main.storyboard */ = { 692 | isa = PBXVariantGroup; 693 | children = ( 694 | 64CD6C371FAA2175009B4F9A /* Base */, 695 | ); 696 | name = Main.storyboard; 697 | sourceTree = ""; 698 | }; 699 | 64CD6C3B1FAA2175009B4F9A /* LaunchScreen.storyboard */ = { 700 | isa = PBXVariantGroup; 701 | children = ( 702 | 64CD6C3C1FAA2175009B4F9A /* Base */, 703 | ); 704 | name = LaunchScreen.storyboard; 705 | sourceTree = ""; 706 | }; 707 | /* End PBXVariantGroup section */ 708 | 709 | /* Begin XCBuildConfiguration section */ 710 | 52D6D98E1BEFF229002C0205 /* Debug */ = { 711 | isa = XCBuildConfiguration; 712 | buildSettings = { 713 | ALWAYS_SEARCH_USER_PATHS = NO; 714 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 715 | CLANG_CXX_LIBRARY = "libc++"; 716 | CLANG_ENABLE_MODULES = YES; 717 | CLANG_ENABLE_OBJC_ARC = YES; 718 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 719 | CLANG_WARN_BOOL_CONVERSION = YES; 720 | CLANG_WARN_COMMA = YES; 721 | CLANG_WARN_CONSTANT_CONVERSION = YES; 722 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 723 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 724 | CLANG_WARN_EMPTY_BODY = YES; 725 | CLANG_WARN_ENUM_CONVERSION = YES; 726 | CLANG_WARN_INFINITE_RECURSION = YES; 727 | CLANG_WARN_INT_CONVERSION = YES; 728 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 729 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 730 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 731 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 732 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 733 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 734 | CLANG_WARN_STRICT_PROTOTYPES = YES; 735 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 736 | CLANG_WARN_UNREACHABLE_CODE = YES; 737 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 738 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 739 | COPY_PHASE_STRIP = NO; 740 | CURRENT_PROJECT_VERSION = 1; 741 | DEBUG_INFORMATION_FORMAT = dwarf; 742 | ENABLE_STRICT_OBJC_MSGSEND = YES; 743 | ENABLE_TESTABILITY = YES; 744 | GCC_C_LANGUAGE_STANDARD = gnu99; 745 | GCC_DYNAMIC_NO_PIC = NO; 746 | GCC_NO_COMMON_BLOCKS = YES; 747 | GCC_OPTIMIZATION_LEVEL = 0; 748 | GCC_PREPROCESSOR_DEFINITIONS = ( 749 | "DEBUG=1", 750 | "$(inherited)", 751 | ); 752 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 753 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 754 | GCC_WARN_UNDECLARED_SELECTOR = YES; 755 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 756 | GCC_WARN_UNUSED_FUNCTION = YES; 757 | GCC_WARN_UNUSED_VARIABLE = YES; 758 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 759 | MTL_ENABLE_DEBUG_INFO = YES; 760 | ONLY_ACTIVE_ARCH = YES; 761 | SDKROOT = iphoneos; 762 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 763 | SWIFT_VERSION = 4.0; 764 | TARGETED_DEVICE_FAMILY = "1,2"; 765 | VERSIONING_SYSTEM = "apple-generic"; 766 | VERSION_INFO_PREFIX = ""; 767 | }; 768 | name = Debug; 769 | }; 770 | 52D6D98F1BEFF229002C0205 /* Release */ = { 771 | isa = XCBuildConfiguration; 772 | buildSettings = { 773 | ALWAYS_SEARCH_USER_PATHS = NO; 774 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 775 | CLANG_CXX_LIBRARY = "libc++"; 776 | CLANG_ENABLE_MODULES = YES; 777 | CLANG_ENABLE_OBJC_ARC = YES; 778 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 779 | CLANG_WARN_BOOL_CONVERSION = YES; 780 | CLANG_WARN_COMMA = YES; 781 | CLANG_WARN_CONSTANT_CONVERSION = YES; 782 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 783 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 784 | CLANG_WARN_EMPTY_BODY = YES; 785 | CLANG_WARN_ENUM_CONVERSION = YES; 786 | CLANG_WARN_INFINITE_RECURSION = YES; 787 | CLANG_WARN_INT_CONVERSION = YES; 788 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 789 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 790 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 791 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 792 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 793 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 794 | CLANG_WARN_STRICT_PROTOTYPES = YES; 795 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 796 | CLANG_WARN_UNREACHABLE_CODE = YES; 797 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 798 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 799 | COPY_PHASE_STRIP = NO; 800 | CURRENT_PROJECT_VERSION = 1; 801 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 802 | ENABLE_NS_ASSERTIONS = NO; 803 | ENABLE_STRICT_OBJC_MSGSEND = YES; 804 | GCC_C_LANGUAGE_STANDARD = gnu99; 805 | GCC_NO_COMMON_BLOCKS = YES; 806 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 807 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 808 | GCC_WARN_UNDECLARED_SELECTOR = YES; 809 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 810 | GCC_WARN_UNUSED_FUNCTION = YES; 811 | GCC_WARN_UNUSED_VARIABLE = YES; 812 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 813 | MTL_ENABLE_DEBUG_INFO = NO; 814 | SDKROOT = iphoneos; 815 | SWIFT_VERSION = 4.0; 816 | TARGETED_DEVICE_FAMILY = "1,2"; 817 | VALIDATE_PRODUCT = YES; 818 | VERSIONING_SYSTEM = "apple-generic"; 819 | VERSION_INFO_PREFIX = ""; 820 | }; 821 | name = Release; 822 | }; 823 | 52D6D9911BEFF229002C0205 /* Debug */ = { 824 | isa = XCBuildConfiguration; 825 | buildSettings = { 826 | APPLICATION_EXTENSION_API_ONLY = YES; 827 | CLANG_ENABLE_MODULES = YES; 828 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 829 | DEFINES_MODULE = YES; 830 | DYLIB_COMPATIBILITY_VERSION = 1; 831 | DYLIB_CURRENT_VERSION = 1; 832 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 833 | INFOPLIST_FILE = Configs/UAParserSwift.plist; 834 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 835 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 836 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 837 | ONLY_ACTIVE_ARCH = NO; 838 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-iOS"; 839 | PRODUCT_NAME = UAParserSwift; 840 | SKIP_INSTALL = YES; 841 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 842 | SWIFT_VERSION = 5.0; 843 | }; 844 | name = Debug; 845 | }; 846 | 52D6D9921BEFF229002C0205 /* Release */ = { 847 | isa = XCBuildConfiguration; 848 | buildSettings = { 849 | APPLICATION_EXTENSION_API_ONLY = YES; 850 | CLANG_ENABLE_MODULES = YES; 851 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 852 | DEFINES_MODULE = YES; 853 | DYLIB_COMPATIBILITY_VERSION = 1; 854 | DYLIB_CURRENT_VERSION = 1; 855 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 856 | INFOPLIST_FILE = Configs/UAParserSwift.plist; 857 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 858 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 859 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 860 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-iOS"; 861 | PRODUCT_NAME = UAParserSwift; 862 | SKIP_INSTALL = YES; 863 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 864 | SWIFT_VERSION = 5.0; 865 | }; 866 | name = Release; 867 | }; 868 | 52D6D9941BEFF229002C0205 /* Debug */ = { 869 | isa = XCBuildConfiguration; 870 | buildSettings = { 871 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 872 | CLANG_ENABLE_MODULES = YES; 873 | INFOPLIST_FILE = Configs/UAParserSwiftTests.plist; 874 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 875 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-iOS-Tests"; 876 | PRODUCT_NAME = "$(TARGET_NAME)"; 877 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 878 | SWIFT_VERSION = 4.0; 879 | }; 880 | name = Debug; 881 | }; 882 | 52D6D9951BEFF229002C0205 /* Release */ = { 883 | isa = XCBuildConfiguration; 884 | buildSettings = { 885 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 886 | CLANG_ENABLE_MODULES = YES; 887 | INFOPLIST_FILE = Configs/UAParserSwiftTests.plist; 888 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 889 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-iOS-Tests"; 890 | PRODUCT_NAME = "$(TARGET_NAME)"; 891 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 892 | SWIFT_VERSION = 4.0; 893 | }; 894 | name = Release; 895 | }; 896 | 52D6D9E81BEFFF6E002C0205 /* Debug */ = { 897 | isa = XCBuildConfiguration; 898 | buildSettings = { 899 | APPLICATION_EXTENSION_API_ONLY = YES; 900 | CLANG_ENABLE_MODULES = YES; 901 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 902 | DEFINES_MODULE = YES; 903 | DYLIB_COMPATIBILITY_VERSION = 1; 904 | DYLIB_CURRENT_VERSION = 1; 905 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 906 | INFOPLIST_FILE = Configs/UAParserSwift.plist; 907 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 908 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 909 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-watchOS"; 910 | PRODUCT_NAME = UAParserSwift; 911 | SDKROOT = watchos; 912 | SKIP_INSTALL = YES; 913 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 914 | SWIFT_VERSION = 4.0; 915 | TARGETED_DEVICE_FAMILY = 4; 916 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 917 | }; 918 | name = Debug; 919 | }; 920 | 52D6D9E91BEFFF6E002C0205 /* Release */ = { 921 | isa = XCBuildConfiguration; 922 | buildSettings = { 923 | APPLICATION_EXTENSION_API_ONLY = YES; 924 | CLANG_ENABLE_MODULES = YES; 925 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 926 | DEFINES_MODULE = YES; 927 | DYLIB_COMPATIBILITY_VERSION = 1; 928 | DYLIB_CURRENT_VERSION = 1; 929 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 930 | INFOPLIST_FILE = Configs/UAParserSwift.plist; 931 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 932 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 933 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-watchOS"; 934 | PRODUCT_NAME = UAParserSwift; 935 | SDKROOT = watchos; 936 | SKIP_INSTALL = YES; 937 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 938 | SWIFT_VERSION = 4.0; 939 | TARGETED_DEVICE_FAMILY = 4; 940 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 941 | }; 942 | name = Release; 943 | }; 944 | 52D6DA021BEFFFBE002C0205 /* Debug */ = { 945 | isa = XCBuildConfiguration; 946 | buildSettings = { 947 | APPLICATION_EXTENSION_API_ONLY = YES; 948 | CLANG_ENABLE_MODULES = YES; 949 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 950 | DEFINES_MODULE = YES; 951 | DYLIB_COMPATIBILITY_VERSION = 1; 952 | DYLIB_CURRENT_VERSION = 1; 953 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 954 | INFOPLIST_FILE = Configs/UAParserSwift.plist; 955 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 956 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 957 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-tvOS"; 958 | PRODUCT_NAME = UAParserSwift; 959 | SDKROOT = appletvos; 960 | SKIP_INSTALL = YES; 961 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 962 | SWIFT_VERSION = 4.0; 963 | TARGETED_DEVICE_FAMILY = 3; 964 | TVOS_DEPLOYMENT_TARGET = 12.0; 965 | }; 966 | name = Debug; 967 | }; 968 | 52D6DA031BEFFFBE002C0205 /* Release */ = { 969 | isa = XCBuildConfiguration; 970 | buildSettings = { 971 | APPLICATION_EXTENSION_API_ONLY = YES; 972 | CLANG_ENABLE_MODULES = YES; 973 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 974 | DEFINES_MODULE = YES; 975 | DYLIB_COMPATIBILITY_VERSION = 1; 976 | DYLIB_CURRENT_VERSION = 1; 977 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 978 | INFOPLIST_FILE = Configs/UAParserSwift.plist; 979 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 980 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 981 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-tvOS"; 982 | PRODUCT_NAME = UAParserSwift; 983 | SDKROOT = appletvos; 984 | SKIP_INSTALL = YES; 985 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 986 | SWIFT_VERSION = 4.0; 987 | TARGETED_DEVICE_FAMILY = 3; 988 | TVOS_DEPLOYMENT_TARGET = 12.0; 989 | }; 990 | name = Release; 991 | }; 992 | 52D6DA211BF000BD002C0205 /* Debug */ = { 993 | isa = XCBuildConfiguration; 994 | buildSettings = { 995 | APPLICATION_EXTENSION_API_ONLY = YES; 996 | CLANG_ENABLE_MODULES = YES; 997 | CODE_SIGN_IDENTITY = "-"; 998 | COMBINE_HIDPI_IMAGES = YES; 999 | DEFINES_MODULE = YES; 1000 | DYLIB_COMPATIBILITY_VERSION = 1; 1001 | DYLIB_CURRENT_VERSION = 1; 1002 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1003 | FRAMEWORK_VERSION = A; 1004 | INFOPLIST_FILE = Configs/UAParserSwift.plist; 1005 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1006 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 1007 | MACOSX_DEPLOYMENT_TARGET = 10.10; 1008 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-macOS"; 1009 | PRODUCT_NAME = UAParserSwift; 1010 | SDKROOT = macosx; 1011 | SKIP_INSTALL = YES; 1012 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 1013 | SWIFT_VERSION = 4.0; 1014 | }; 1015 | name = Debug; 1016 | }; 1017 | 52D6DA221BF000BD002C0205 /* Release */ = { 1018 | isa = XCBuildConfiguration; 1019 | buildSettings = { 1020 | APPLICATION_EXTENSION_API_ONLY = YES; 1021 | CLANG_ENABLE_MODULES = YES; 1022 | CODE_SIGN_IDENTITY = "-"; 1023 | COMBINE_HIDPI_IMAGES = YES; 1024 | DEFINES_MODULE = YES; 1025 | DYLIB_COMPATIBILITY_VERSION = 1; 1026 | DYLIB_CURRENT_VERSION = 1; 1027 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1028 | FRAMEWORK_VERSION = A; 1029 | INFOPLIST_FILE = Configs/UAParserSwift.plist; 1030 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1031 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 1032 | MACOSX_DEPLOYMENT_TARGET = 10.10; 1033 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-macOS"; 1034 | PRODUCT_NAME = UAParserSwift; 1035 | SDKROOT = macosx; 1036 | SKIP_INSTALL = YES; 1037 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1038 | SWIFT_VERSION = 4.0; 1039 | }; 1040 | name = Release; 1041 | }; 1042 | 64CD6C3F1FAA2175009B4F9A /* Debug */ = { 1043 | isa = XCBuildConfiguration; 1044 | buildSettings = { 1045 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1046 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 1047 | CLANG_ANALYZER_NONNULL = YES; 1048 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 1049 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 1050 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 1051 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 1052 | CODE_SIGN_IDENTITY = "iPhone Developer"; 1053 | CODE_SIGN_STYLE = Automatic; 1054 | GCC_C_LANGUAGE_STANDARD = gnu11; 1055 | INFOPLIST_FILE = TestApplication/Info.plist; 1056 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 1057 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 1058 | LIBRARY_SEARCH_PATHS = ""; 1059 | PRODUCT_BUNDLE_IDENTIFIER = com.danielemargutti.TestApplication; 1060 | PRODUCT_NAME = "$(TARGET_NAME)"; 1061 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 1062 | SWIFT_VERSION = 5.0; 1063 | TARGETED_DEVICE_FAMILY = "1,2"; 1064 | }; 1065 | name = Debug; 1066 | }; 1067 | 64CD6C401FAA2175009B4F9A /* Release */ = { 1068 | isa = XCBuildConfiguration; 1069 | buildSettings = { 1070 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1071 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 1072 | CLANG_ANALYZER_NONNULL = YES; 1073 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 1074 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 1075 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 1076 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 1077 | CODE_SIGN_IDENTITY = "iPhone Developer"; 1078 | CODE_SIGN_STYLE = Automatic; 1079 | GCC_C_LANGUAGE_STANDARD = gnu11; 1080 | INFOPLIST_FILE = TestApplication/Info.plist; 1081 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 1082 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 1083 | LIBRARY_SEARCH_PATHS = ""; 1084 | PRODUCT_BUNDLE_IDENTIFIER = com.danielemargutti.TestApplication; 1085 | PRODUCT_NAME = "$(TARGET_NAME)"; 1086 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1087 | SWIFT_VERSION = 5.0; 1088 | TARGETED_DEVICE_FAMILY = "1,2"; 1089 | }; 1090 | name = Release; 1091 | }; 1092 | DD7502831C68FCFC006590AF /* Debug */ = { 1093 | isa = XCBuildConfiguration; 1094 | buildSettings = { 1095 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1096 | CODE_SIGN_IDENTITY = "-"; 1097 | COMBINE_HIDPI_IMAGES = YES; 1098 | INFOPLIST_FILE = Configs/UAParserSwiftTests.plist; 1099 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 1100 | MACOSX_DEPLOYMENT_TARGET = 10.11; 1101 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-macOS-Tests"; 1102 | PRODUCT_NAME = "$(TARGET_NAME)"; 1103 | SDKROOT = macosx; 1104 | SWIFT_VERSION = 4.0; 1105 | }; 1106 | name = Debug; 1107 | }; 1108 | DD7502841C68FCFC006590AF /* Release */ = { 1109 | isa = XCBuildConfiguration; 1110 | buildSettings = { 1111 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1112 | CODE_SIGN_IDENTITY = "-"; 1113 | COMBINE_HIDPI_IMAGES = YES; 1114 | INFOPLIST_FILE = Configs/UAParserSwiftTests.plist; 1115 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 1116 | MACOSX_DEPLOYMENT_TARGET = 10.11; 1117 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-macOS-Tests"; 1118 | PRODUCT_NAME = "$(TARGET_NAME)"; 1119 | SDKROOT = macosx; 1120 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1121 | SWIFT_VERSION = 4.0; 1122 | }; 1123 | name = Release; 1124 | }; 1125 | DD7502961C690C7A006590AF /* Debug */ = { 1126 | isa = XCBuildConfiguration; 1127 | buildSettings = { 1128 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1129 | INFOPLIST_FILE = Configs/UAParserSwiftTests.plist; 1130 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1131 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-tvOS-Tests"; 1132 | PRODUCT_NAME = "$(TARGET_NAME)"; 1133 | SDKROOT = appletvos; 1134 | SWIFT_VERSION = 4.0; 1135 | TVOS_DEPLOYMENT_TARGET = 12.0; 1136 | }; 1137 | name = Debug; 1138 | }; 1139 | DD7502971C690C7A006590AF /* Release */ = { 1140 | isa = XCBuildConfiguration; 1141 | buildSettings = { 1142 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1143 | INFOPLIST_FILE = Configs/UAParserSwiftTests.plist; 1144 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1145 | PRODUCT_BUNDLE_IDENTIFIER = "com.UAParserSwift.UAParserSwift-tvOS-Tests"; 1146 | PRODUCT_NAME = "$(TARGET_NAME)"; 1147 | SDKROOT = appletvos; 1148 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1149 | SWIFT_VERSION = 4.0; 1150 | TVOS_DEPLOYMENT_TARGET = 12.0; 1151 | }; 1152 | name = Release; 1153 | }; 1154 | /* End XCBuildConfiguration section */ 1155 | 1156 | /* Begin XCConfigurationList section */ 1157 | 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "UAParserSwift" */ = { 1158 | isa = XCConfigurationList; 1159 | buildConfigurations = ( 1160 | 52D6D98E1BEFF229002C0205 /* Debug */, 1161 | 52D6D98F1BEFF229002C0205 /* Release */, 1162 | ); 1163 | defaultConfigurationIsVisible = 0; 1164 | defaultConfigurationName = Release; 1165 | }; 1166 | 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-iOS" */ = { 1167 | isa = XCConfigurationList; 1168 | buildConfigurations = ( 1169 | 52D6D9911BEFF229002C0205 /* Debug */, 1170 | 52D6D9921BEFF229002C0205 /* Release */, 1171 | ); 1172 | defaultConfigurationIsVisible = 0; 1173 | defaultConfigurationName = Release; 1174 | }; 1175 | 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-iOS Tests" */ = { 1176 | isa = XCConfigurationList; 1177 | buildConfigurations = ( 1178 | 52D6D9941BEFF229002C0205 /* Debug */, 1179 | 52D6D9951BEFF229002C0205 /* Release */, 1180 | ); 1181 | defaultConfigurationIsVisible = 0; 1182 | defaultConfigurationName = Release; 1183 | }; 1184 | 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-watchOS" */ = { 1185 | isa = XCConfigurationList; 1186 | buildConfigurations = ( 1187 | 52D6D9E81BEFFF6E002C0205 /* Debug */, 1188 | 52D6D9E91BEFFF6E002C0205 /* Release */, 1189 | ); 1190 | defaultConfigurationIsVisible = 0; 1191 | defaultConfigurationName = Release; 1192 | }; 1193 | 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-tvOS" */ = { 1194 | isa = XCConfigurationList; 1195 | buildConfigurations = ( 1196 | 52D6DA021BEFFFBE002C0205 /* Debug */, 1197 | 52D6DA031BEFFFBE002C0205 /* Release */, 1198 | ); 1199 | defaultConfigurationIsVisible = 0; 1200 | defaultConfigurationName = Release; 1201 | }; 1202 | 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "UAParserSwift-macOS" */ = { 1203 | isa = XCConfigurationList; 1204 | buildConfigurations = ( 1205 | 52D6DA211BF000BD002C0205 /* Debug */, 1206 | 52D6DA221BF000BD002C0205 /* Release */, 1207 | ); 1208 | defaultConfigurationIsVisible = 0; 1209 | defaultConfigurationName = Release; 1210 | }; 1211 | 64CD6C411FAA2175009B4F9A /* Build configuration list for PBXNativeTarget "TestApplication" */ = { 1212 | isa = XCConfigurationList; 1213 | buildConfigurations = ( 1214 | 64CD6C3F1FAA2175009B4F9A /* Debug */, 1215 | 64CD6C401FAA2175009B4F9A /* Release */, 1216 | ); 1217 | defaultConfigurationIsVisible = 0; 1218 | defaultConfigurationName = Release; 1219 | }; 1220 | DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "UAParserSwift-macOS Tests" */ = { 1221 | isa = XCConfigurationList; 1222 | buildConfigurations = ( 1223 | DD7502831C68FCFC006590AF /* Debug */, 1224 | DD7502841C68FCFC006590AF /* Release */, 1225 | ); 1226 | defaultConfigurationIsVisible = 0; 1227 | defaultConfigurationName = Release; 1228 | }; 1229 | DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "UAParserSwift-tvOS Tests" */ = { 1230 | isa = XCConfigurationList; 1231 | buildConfigurations = ( 1232 | DD7502961C690C7A006590AF /* Debug */, 1233 | DD7502971C690C7A006590AF /* Release */, 1234 | ); 1235 | defaultConfigurationIsVisible = 0; 1236 | defaultConfigurationName = Release; 1237 | }; 1238 | /* End XCConfigurationList section */ 1239 | }; 1240 | rootObject = 52D6D9731BEFF229002C0205 /* Project object */; 1241 | } 1242 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/project.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malcommac/UAParserSwift/a8057c7cff60db2cdf31d0a0a68ce430754ab64e/UAParserSwift.xcodeproj/project.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/xcshareddata/xcschemes/UAParserSwift-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/xcshareddata/xcschemes/UAParserSwift-macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/xcshareddata/xcschemes/UAParserSwift-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/xcshareddata/xcschemes/UAParserSwift-watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 44 | 45 | 51 | 52 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/xcuserdata/daniele.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /UAParserSwift.xcodeproj/xcuserdata/daniele.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TestApplication.xcscheme 8 | 9 | orderHint 10 | 4 11 | 12 | TestApplication.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 4 16 | 17 | UAParserSwift-iOS.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 0 21 | 22 | UAParserSwift-macOS.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 1 26 | 27 | UAParserSwift-tvOS.xcscheme_^#shared#^_ 28 | 29 | orderHint 30 | 2 31 | 32 | UAParserSwift-watchOS.xcscheme_^#shared#^_ 33 | 34 | orderHint 35 | 3 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malcommac/UAParserSwift/a8057c7cff60db2cdf31d0a0a68ce430754ab64e/banner.png --------------------------------------------------------------------------------