diff --git a/.travis.yml b/.travis.yml index db77388..02d31a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,14 +3,13 @@ language: objective-c workspace: ChordDetector.xcworkspace scheme: ChordDetector test_scheme: ChordDetectorTests -osx_image: xcode9 -xcode_sdk: macosx10.12 +osx_image: xcode10 +xcode_sdk: macosx10.14 before_install: - gem install cocoapods - pod repo update script: - - pod install - - xcodebuild -workspace ChordDetector.xcworkspace -scheme ChordDetector ONLY_ACTIVE_ARCH=NO CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO - - xcodebuild test -workspace ChordDetector.xcworkspace -scheme ChordDetectorTests ONLY_ACTIVE_ARCH=NO CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO + - xcodebuild -workspace ChordDetector.xcworkspace -scheme ChordDetector ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" + - xcodebuild -workspace ChordDetector.xcworkspace -scheme ChordDetectorTests test ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" diff --git a/ChordDetector.xcodeproj/project.pbxproj b/ChordDetector.xcodeproj/project.pbxproj index 092c33e..e43846b 100644 --- a/ChordDetector.xcodeproj/project.pbxproj +++ b/ChordDetector.xcodeproj/project.pbxproj @@ -139,7 +139,6 @@ B27643A41E8494DB00B67425 /* Frameworks */, B27643A51E8494DB00B67425 /* Resources */, 2CC3CCCC95854AE99F8E8B3C /* [CP] Embed Pods Frameworks */, - B003C2B5475D05DEE18BA2FE /* [CP] Copy Pods Resources */, B2C3DA611E85F99900BD3074 /* Crashlytics */, ); buildRules = ( @@ -160,7 +159,6 @@ B2C64CBF1E8E6A0200E7B74F /* Frameworks */, B2C64CC01E8E6A0200E7B74F /* Resources */, DA5A3469DDD57EC2402AAEC9 /* [CP] Embed Pods Frameworks */, - 6C5467B394CC7FF835CEFE0B /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -179,12 +177,13 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0830; - LastUpgradeCheck = 0920; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = cemolcay; TargetAttributes = { B27643A61E8494DB00B67425 = { CreatedOnToolsVersion = 8.2.1; DevelopmentTeam = 77Y3N48SNF; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.Sandbox = { @@ -195,7 +194,7 @@ B2C64CC11E8E6A0200E7B74F = { CreatedOnToolsVersion = 8.3; DevelopmentTeam = 77Y3N48SNF; - LastSwiftMigration = 0920; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; TestTargetID = B27643A61E8494DB00B67425; }; @@ -246,48 +245,20 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-ChordDetector/Pods-ChordDetector-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-ChordDetector/Pods-ChordDetector-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/Kanna/Kanna.framework", + "${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kanna.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ChordDetector/Pods-ChordDetector-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 6C5467B394CC7FF835CEFE0B /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ChordDetectorTests/Pods-ChordDetectorTests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - B003C2B5475D05DEE18BA2FE /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ChordDetector/Pods-ChordDetector-resources.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ChordDetector/Pods-ChordDetector-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; B2C3DA611E85F99900BD3074 /* Crashlytics */ = { @@ -346,18 +317,20 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-ChordDetectorTests/Pods-ChordDetectorTests-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-ChordDetectorTests/Pods-ChordDetectorTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/Kanna/Kanna.framework", + "${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kanna.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ChordDetectorTests/Pods-ChordDetectorTests-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ChordDetectorTests/Pods-ChordDetectorTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -415,6 +388,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -422,6 +396,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -471,6 +446,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -478,6 +454,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -521,7 +498,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = com.cemolcay.chordDetector; PRODUCT_NAME = "Chord Detector"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -539,7 +516,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = com.cemolcay.chordDetector; PRODUCT_NAME = "Chord Detector"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -557,8 +534,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.example.ChordDetectorTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Chord Detector.app/Contents/MacOS/Chord Detector"; }; name = Debug; @@ -577,8 +553,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.example.ChordDetectorTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Chord Detector.app/Contents/MacOS/Chord Detector"; }; name = Release; diff --git a/ChordDetector.xcodeproj/xcshareddata/xcschemes/ChordDetector.xcscheme b/ChordDetector.xcodeproj/xcshareddata/xcschemes/ChordDetector.xcscheme index 310fabf..f72d5b2 100644 --- a/ChordDetector.xcodeproj/xcshareddata/xcschemes/ChordDetector.xcscheme +++ b/ChordDetector.xcodeproj/xcshareddata/xcschemes/ChordDetector.xcscheme @@ -1,6 +1,6 @@ - - - - diff --git a/ChordDetector.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ChordDetector.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ChordDetector.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ChordDetector.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ChordDetector.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..949b678 --- /dev/null +++ b/ChordDetector.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + BuildSystemType + Original + + diff --git a/ChordDetector/AppDelegate.swift b/ChordDetector/AppDelegate.swift index 396a754..cfd5d19 100644 --- a/ChordDetector/AppDelegate.swift +++ b/ChordDetector/AppDelegate.swift @@ -20,7 +20,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { // StatusBarItem statusItem.menu = menu if let button = statusItem.button { - button.image = NSImage(named: NSImage.Name(rawValue: "menuBar")) + button.image = NSImage(named: "menuBar") button.imageScaling = .scaleProportionallyUpOrDown } diff --git a/ChordDetector/ChordDetector.swift b/ChordDetector/ChordDetector.swift index 1fed247..6617b78 100644 --- a/ChordDetector/ChordDetector.swift +++ b/ChordDetector/ChordDetector.swift @@ -9,48 +9,30 @@ import Cocoa import Alamofire import Kanna +import SwiftyJSON // MARK: - HistoryItem -class HistoryItem: NSObject, NSCoding { +struct HistoryItem: Codable, Equatable { var name: String var url: String init(name: String, url: String) { self.name = name self.url = url - super.init() - } - convenience init?(notification: NSUserNotification) { + init?(notification: NSUserNotification) { guard let name = notification.userInfo?["name"] as? String, let url = notification.userInfo?["url"] as? String else { return nil } - self.init(name: name, url: url) - } - - // MARK: NSCoding - - required convenience init?(coder aDecoder: NSCoder) { - guard let name = aDecoder.decodeObject(forKey: "name") as? String, - let url = aDecoder.decodeObject(forKey: "url") as? String - else { return nil } - self.init(name: name, url: url) - } - - func encode(with aCoder: NSCoder) { - aCoder.encode(name, forKey: "name") - aCoder.encode(url, forKey: "url") + self = HistoryItem(name: name, url: url) } // MARK: Equatable - override func isEqual(_ object: Any?) -> Bool { - if let item = object as? HistoryItem { - return item.name == name && item.url == url - } - return super.isEqual(object) + static func == (lhs: HistoryItem, rhs: HistoryItem) -> Bool { + return lhs.name == rhs.name && lhs.url == rhs.url } } @@ -67,14 +49,15 @@ class ChordDetector: NSObject, NSUserNotificationCenterDelegate { var history: [HistoryItem] { get { - if let data = UserDefaults.standard.object(forKey: historyKey) as? Data, - let history = NSKeyedUnarchiver.unarchiveObject(with: data) as? [HistoryItem] { + if let data = UserDefaults.standard.data(forKey: historyKey), + let history = try? PropertyListDecoder().decode([HistoryItem].self, from: data) { return history } // Create new let defaults = UserDefaults.standard - defaults.set(NSKeyedArchiver.archivedData(withRootObject: [HistoryItem]()), forKey: historyKey) + guard let data = try? PropertyListEncoder().encode([HistoryItem]()) else { return [] } + defaults.set(data, forKey: historyKey) defaults.synchronize() return [] } set { @@ -84,7 +67,8 @@ class ChordDetector: NSObject, NSUserNotificationCenterDelegate { } let defaults = UserDefaults.standard - defaults.set(NSKeyedArchiver.archivedData(withRootObject: newHistory), forKey: historyKey) + guard let data = try? PropertyListEncoder().encode(newHistory) else { return } + defaults.set(data, forKey: historyKey) defaults.synchronize() } } @@ -157,17 +141,28 @@ class ChordDetector: NSObject, NSUserNotificationCenterDelegate { private func parseChords(string: String, artist: String, song: String) { guard let html = try? HTML(html: string, encoding: .utf8) else { return } - - // Get chord rows from result table sorted by their rating and parse their urls - let chords = html - .xpath("//table[@class=\"tresults \"]//tr[contains(.,\"chords\")]") - .sorted(by: { - (($0.xpath("./td/span/b[@class=\"ratdig\"]").first?.text ?? "") as NSString).intValue > - (($1.xpath("./td/span/b[@class=\"ratdig\"]").first?.text ?? "") as NSString).intValue - }).flatMap({ $0.xpath("./td/div/a[@class=\"song result-link js-search-spelling-link\"]").first }) - - // Get most rated chord url - guard let url = chords.first?["href"] else { return } + let regexPattern = "(?<= window.UGAPP.store.page = )(.*)(?=;)" + + guard + let script = html.xpath("//script") + .compactMap({ $0.text }) + .filter({ $0.contains("window.UGAPP.store.page") }) + .first, + let regex = try? NSRegularExpression(pattern: regexPattern, options: []), + let match = regex.firstMatch(in: script, options: [], range: NSRange(0.. $1.1["rating"].doubleValue }) + .first.map({ $0.1 }), + let url = result["tab_url"].url + else { return } // Push a notification after 1sec of song change to bypass iTunes/Spotify notification. let notification = NSUserNotification() @@ -176,11 +171,11 @@ class ChordDetector: NSObject, NSUserNotificationCenterDelegate { notification.userInfo = [ "type": "chord", "name": "\(artist) - \(song)", - "url": url, + "url": url.absoluteString, ] Timer.scheduledTimer( - timeInterval: 1, + timeInterval: 5, target: self, selector: #selector(fireNotification(timer:)), userInfo: ["notification": notification], diff --git a/ChordDetector/Info.plist b/ChordDetector/Info.plist index e00ac65..b639d6f 100644 --- a/ChordDetector/Info.plist +++ b/ChordDetector/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3 + 2.0 CFBundleVersion - 9 + 14 Fabric APIKey @@ -40,6 +40,8 @@ $(MACOSX_DEPLOYMENT_TARGET) LSUIElement + NSAppleEventsUsageDescription + Allow ChordDetector to listen song changes on iTunes or Spotify. NSHumanReadableCopyright Copyright © 2017 cemolcay. All rights reserved. NSMainStoryboardFile diff --git a/ChordDetectorTests/ChordDetectorTests.swift b/ChordDetectorTests/ChordDetectorTests.swift index 31c2982..c78d5d5 100644 --- a/ChordDetectorTests/ChordDetectorTests.swift +++ b/ChordDetectorTests/ChordDetectorTests.swift @@ -9,6 +9,7 @@ import XCTest import Kanna import Alamofire +import SwiftyJSON class ChordDetectorTests: XCTestCase { @@ -31,32 +32,50 @@ class ChordDetectorTests: XCTestCase { .expires: Date(timeIntervalSinceNow: 365*24*60) ]) else { fatalError("Old ultimate-guitar cookie no set.") } Alamofire.SessionManager.default.session.configuration.httpCookieStorage?.setCookie(cookie) - - Alamofire.request(chordUrl).responseString(completionHandler: {response in + + // Make request + let networkExpectation = expectation(description: "UltimateGuitar network request expectation.") + Alamofire.request(chordUrl) + .responseString(completionHandler: { response in switch response.result { case .success(let string): - guard let html = try? HTML(html: string, encoding: .utf8) else { return XCTFail("HTML not parsed.") } - - // Parse chord rows in result table and sort them in order to rating - let chords = html - .xpath("//table[@class=\"tresults \"]//tr[contains(.,\"chords\")]") - .sorted(by: { - (($0.xpath("./td/span/b[@class=\"ratdig\"]").first?.text ?? "") as NSString).intValue > - (($1.xpath("./td/span/b[@class=\"ratdig\"]").first?.text ?? "") as NSString).intValue - }) - XCTAssertGreaterThan(chords.count, 0, "No chord found.") - - // Parse urls of chord rows - let urls = chords.flatMap({ $0.xpath("./td/div/a[@class=\"song result-link js-search-spelling-link\"]").first }) - XCTAssertGreaterThan(urls.count, 0, "Chord URLs not parsed.") - - // Get most rated chord url - let url = urls.first?["href"] - XCTAssertNotNil(url, "Chord URL not found.") + guard let html = try? HTML(html: string, encoding: .utf8) + else { return XCTFail("HTML not parsed.") } + + let regexPattern = "(?<= window.UGAPP.store.page = )(.*)(?=;)" + + guard + let script = html.xpath("//script") + .compactMap({ $0.text }) + .filter({ $0.contains("window.UGAPP.store.page") }) + .first, + let regex = try? NSRegularExpression(pattern: regexPattern, options: []), + let match = regex.firstMatch(in: script, options: [], range: NSRange(0.. $1.1["rating"].doubleValue }) + .first + .map({ $0.1 }) + else { return XCTFail("Can not find the result") } + + let url = result["tab_url"].url + XCTAssertNotNil(url, "Can not get the URL") + networkExpectation.fulfill() + case .failure: // Request error XCTFail("URL Request error. Check internet connection.") } }) + + wait(for: [networkExpectation], timeout: 10.0) } } diff --git a/Podfile b/Podfile index 0e3de40..a5b59a3 100644 --- a/Podfile +++ b/Podfile @@ -1,16 +1,19 @@ # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' +swift_version='4.2' target 'ChordDetector' do use_frameworks! pod 'Alamofire' - pod 'Kanna', :git => 'https://github.com/tid-kijyun/Kanna.git', :branch => 'feature/v4.0.0' + pod 'Kanna' #, :git => 'https://github.com/tid-kijyun/Kanna.git', :branch => 'feature/v4.0.0' pod 'Fabric' pod 'Crashlytics' + pod 'SwiftyJSON' end target 'ChordDetectorTests' do use_frameworks! pod 'Alamofire' - pod 'Kanna', :git => 'https://github.com/tid-kijyun/Kanna.git', :branch => 'feature/v4.0.0' + pod 'Kanna' #, :git => 'https://github.com/tid-kijyun/Kanna.git', :branch => 'feature/v4.0.0' + pod 'SwiftyJSON' end diff --git a/Podfile.lock b/Podfile.lock index bc7446a..0de8159 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,32 +1,33 @@ PODS: - - Alamofire (4.6.0) - - Crashlytics (3.10.0): - - Fabric (~> 1.7.3) - - Fabric (1.7.3) - - Kanna (4.0.0) + - Alamofire (4.7.3) + - Crashlytics (3.11.0): + - Fabric (~> 1.8.0) + - Fabric (1.8.0) + - Kanna (4.0.2) + - SwiftyJSON (4.2.0) DEPENDENCIES: - Alamofire - Crashlytics - Fabric - - Kanna (from `https://github.com/tid-kijyun/Kanna.git`, branch `feature/v4.0.0`) + - Kanna + - SwiftyJSON -EXTERNAL SOURCES: - Kanna: - :branch: feature/v4.0.0 - :git: https://github.com/tid-kijyun/Kanna.git - -CHECKOUT OPTIONS: - Kanna: - :commit: d14801345da8998d4da4a071006fb7746de3d1eb - :git: https://github.com/tid-kijyun/Kanna.git +SPEC REPOS: + https://github.com/cocoapods/specs.git: + - Alamofire + - Crashlytics + - Fabric + - Kanna + - SwiftyJSON SPEC CHECKSUMS: - Alamofire: f41a599bd63041760b26d393ec1069d9d7b917f4 - Crashlytics: a989ef242b66605577a425733797f810bd2725eb - Fabric: bb495bb9a7a7677c6d03a1f8b83d95bc49b47e41 - Kanna: d5ae2a26472f7e7a474e7f36a9cd8aa2c8c63ad3 + Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568 + Crashlytics: 1448070c1d2731ab71ea7c3faf84ac0f69657287 + Fabric: 4ac1cdfef3004ccd83ce0959b91eda8a6e37df72 + Kanna: c60b61d72554bf04ed1ee074f9b379855cab4892 + SwiftyJSON: c4bcba26dd9ec7a027fc8eade48e2c911f229e96 -PODFILE CHECKSUM: 52c463df8cc5060b662c2ce03b2245a18808c209 +PODFILE CHECKSUM: a1c82a54e0b8323c71acc948e6b63cc637a6fba7 -COCOAPODS: 1.4.0 +COCOAPODS: 1.6.0.beta.1