├── Assets ├── banner.png ├── appstore.png ├── download.png ├── fetch-demo-final.gif ├── favorite-demo-final.gif └── startup-demo-final.gif ├── CDN Fetch ├── Utils │ ├── CDN Fetch-Bridging-Header.h │ ├── LoginItemUtility.h │ └── LoginItemUtility.m ├── Assets.xcassets │ ├── Contents.json │ ├── Fetch.imageset │ │ ├── Fetch.png │ │ └── Contents.json │ ├── Heart.imageset │ │ ├── heart.png │ │ └── Contents.json │ ├── Power.imageset │ │ ├── power.png │ │ └── Contents.json │ ├── BackButton.imageset │ │ ├── Group.png │ │ └── Contents.json │ ├── Settings.imageset │ │ ├── Settings.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── icon_16x16.png │ │ ├── icon_32x32.png │ │ ├── icon_128x128.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_512x512@2x.png │ │ └── Contents.json │ ├── LogoBanner.imageset │ │ ├── LogoBanner.png │ │ └── Contents.json │ └── StatusIcon.imageset │ │ ├── CDNFetch~universal@1x.png │ │ └── Contents.json ├── CDN_Fetch.xcdatamodeld │ ├── .xccurrentversion │ └── CDN_Fetch.xcdatamodel │ │ └── contents ├── main.swift ├── CDN_Fetch.entitlements ├── Helpers │ ├── Notification+Names.swift │ ├── String+Utils.swift │ ├── NSWindow+CenterFrame.swift │ └── NSUserInterfaceItem+Identifiers.swift ├── Models │ ├── AssetType.swift │ └── FavoriteAsset.swift ├── Windows │ └── SettingsWindow.swift ├── Info.plist ├── Views │ ├── NavigationHeader.swift │ ├── ResultCell.swift │ └── AssetCell.swift ├── Controllers │ ├── FavoritesController.swift │ ├── SettingsController.swift │ └── AssetsController.swift └── AppDelegate.swift ├── Pods ├── Target Support Files │ ├── STRegex │ │ ├── STRegex.modulemap │ │ ├── STRegex-dummy.m │ │ ├── STRegex-prefix.pch │ │ ├── STRegex-umbrella.h │ │ ├── STRegex.xcconfig │ │ └── Info.plist │ ├── Alamofire │ │ ├── Alamofire.modulemap │ │ ├── Alamofire-dummy.m │ │ ├── Alamofire-prefix.pch │ │ ├── Alamofire-umbrella.h │ │ ├── Alamofire.xcconfig │ │ └── Info.plist │ ├── CKNavigation │ │ ├── CKNavigation.modulemap │ │ ├── CKNavigation-dummy.m │ │ ├── CKNavigation-prefix.pch │ │ ├── CKNavigation-umbrella.h │ │ ├── CKNavigation.xcconfig │ │ └── Info.plist │ ├── Pods-CDN Fetch │ │ ├── Pods-CDN Fetch.modulemap │ │ ├── Pods-CDN Fetch-dummy.m │ │ ├── Pods-CDN Fetch-umbrella.h │ │ ├── Info.plist │ │ ├── Pods-CDN Fetch.debug.xcconfig │ │ ├── Pods-CDN Fetch.release.xcconfig │ │ ├── Pods-CDN Fetch-acknowledgements.markdown │ │ ├── Pods-CDN Fetch-acknowledgements.plist │ │ ├── Pods-CDN Fetch-frameworks.sh │ │ └── Pods-CDN Fetch-resources.sh │ ├── Pods-CDN FetchTests │ │ ├── Pods-CDN FetchTests.modulemap │ │ ├── Pods-CDN FetchTests-acknowledgements.markdown │ │ ├── Pods-CDN FetchTests-dummy.m │ │ ├── Pods-CDN FetchTests-umbrella.h │ │ ├── Pods-CDN FetchTests.debug.xcconfig │ │ ├── Pods-CDN FetchTests.release.xcconfig │ │ ├── Info.plist │ │ ├── Pods-CDN FetchTests-acknowledgements.plist │ │ ├── Pods-CDN FetchTests-frameworks.sh │ │ └── Pods-CDN FetchTests-resources.sh │ └── Pods-CDN FetchUITests │ │ ├── Pods-CDN FetchUITests.modulemap │ │ ├── Pods-CDN FetchUITests-acknowledgements.markdown │ │ ├── Pods-CDN FetchUITests-dummy.m │ │ ├── Pods-CDN FetchUITests-umbrella.h │ │ ├── Pods-CDN FetchUITests.debug.xcconfig │ │ ├── Pods-CDN FetchUITests.release.xcconfig │ │ ├── Info.plist │ │ ├── Pods-CDN FetchUITests-acknowledgements.plist │ │ ├── Pods-CDN FetchUITests-frameworks.sh │ │ └── Pods-CDN FetchUITests-resources.sh ├── CKNavigation │ ├── Sources │ │ ├── CKNavigation.h │ │ ├── CKNavigatableViewController.swift │ │ ├── CKNavigatable.swift │ │ ├── Stack.swift │ │ └── CKNavigationController.swift │ ├── LICENSE │ └── README.md ├── STRegex │ ├── Source │ │ ├── ThreadLocal.swift │ │ ├── Foundation+Ranges.swift │ │ ├── Memo.swift │ │ ├── Options.swift │ │ ├── MatchResult.swift │ │ └── Regex.swift │ ├── LICENSE.txt │ └── README.md ├── Manifest.lock ├── Alamofire │ ├── LICENSE │ └── Source │ │ ├── DispatchQueue+Alamofire.swift │ │ ├── Notifications.swift │ │ └── Timeline.swift └── Pods.xcodeproj │ ├── xcuserdata │ └── charles.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ ├── Alamofire.xcscheme │ │ ├── CKNavigation.xcscheme │ │ ├── STRegex.xcscheme │ │ ├── Pods-CDN Fetch.xcscheme │ │ ├── Pods-CDN FetchTests.xcscheme │ │ └── Pods-CDN FetchUITests.xcscheme │ └── xcshareddata │ └── xcschemes │ └── CDN FetchTests.xcscheme ├── .travis.yml ├── CHANGELOG.md ├── CDN Fetch.xcworkspace ├── xcuserdata │ └── charles.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ ├── UserInterfaceState.xcuserstate │ │ └── xcschemes │ │ └── xcschememanagement.plist └── contents.xcworkspacedata ├── CDN Fetch.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── charles.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── charles.xcuserdatad │ └── xcschemes │ ├── xcschememanagement.plist │ └── CDN Fetch.xcscheme ├── Podfile.lock ├── Podfile ├── CDN FetchTests ├── Info.plist └── AssetTypeTests.swift ├── CDN FetchUITests ├── Info.plist └── CDN_FetchUITests.swift ├── LICENSE └── README.md /Assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/Assets/banner.png -------------------------------------------------------------------------------- /CDN Fetch/Utils/CDN Fetch-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | /// 2 | #import "LoginItemUtility.h" 3 | -------------------------------------------------------------------------------- /Assets/appstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/Assets/appstore.png -------------------------------------------------------------------------------- /Assets/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/Assets/download.png -------------------------------------------------------------------------------- /Assets/fetch-demo-final.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/Assets/fetch-demo-final.gif -------------------------------------------------------------------------------- /Assets/favorite-demo-final.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/Assets/favorite-demo-final.gif -------------------------------------------------------------------------------- /Assets/startup-demo-final.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/Assets/startup-demo-final.gif -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Fetch.imageset/Fetch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/Fetch.imageset/Fetch.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Heart.imageset/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/Heart.imageset/heart.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Power.imageset/power.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/Power.imageset/power.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/BackButton.imageset/Group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/BackButton.imageset/Group.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Settings.imageset/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/Settings.imageset/Settings.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/LogoBanner.imageset/LogoBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/LogoBanner.imageset/LogoBanner.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /Pods/Target Support Files/STRegex/STRegex.modulemap: -------------------------------------------------------------------------------- 1 | framework module Regex { 2 | umbrella header "STRegex-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | osx_image: xcode9 3 | xcode_project: CDN Fetch.xcworkspace 4 | xcode_scheme: CDN Fetch 5 | podfile: Podfile 6 | before_script: 7 | - pod update 8 | -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v0.1.0 2 | - Initial (pre-release) 3 | # v1.0.0 4 | - Initial (appstore) 5 | - Released to app store 6 | - Fixed favorite selection bug 7 | - Configured Travis CI 8 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire.modulemap: -------------------------------------------------------------------------------- 1 | framework module Alamofire { 2 | umbrella header "Alamofire-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/STRegex/STRegex-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_STRegex : NSObject 3 | @end 4 | @implementation PodsDummy_STRegex 5 | @end 6 | -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/StatusIcon.imageset/CDNFetch~universal@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch/Assets.xcassets/StatusIcon.imageset/CDNFetch~universal@1x.png -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Alamofire : NSObject 3 | @end 4 | @implementation PodsDummy_Alamofire 5 | @end 6 | -------------------------------------------------------------------------------- /CDN Fetch.xcworkspace/xcuserdata/charles.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CKNavigation/CKNavigation.modulemap: -------------------------------------------------------------------------------- 1 | framework module CKNavigation { 2 | umbrella header "CKNavigation-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CKNavigation/CKNavigation-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_CKNavigation : NSObject 3 | @end 4 | @implementation PodsDummy_CKNavigation 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_CDN_Fetch { 2 | umbrella header "Pods-CDN Fetch-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /CDN Fetch.xcworkspace/xcuserdata/charles.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch.xcworkspace/xcuserdata/charles.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_CDN_Fetch : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_CDN_Fetch 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_CDN_FetchTests { 2 | umbrella header "Pods-CDN FetchTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_CDN_FetchTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_CDN_FetchTests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_CDN_FetchUITests { 2 | umbrella header "Pods-CDN FetchUITests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_CDN_FetchUITests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_CDN_FetchUITests 5 | @end 6 | -------------------------------------------------------------------------------- /CDN Fetch.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CDN Fetch.xcodeproj/project.xcworkspace/xcuserdata/charles.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xch4z/cdn-fetch/HEAD/CDN Fetch.xcodeproj/project.xcworkspace/xcuserdata/charles.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/LogoBanner.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LogoBanner.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Pods/Target Support Files/STRegex/STRegex-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CKNavigation/CKNavigation-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /CDN Fetch.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /CDN Fetch.xcworkspace/xcuserdata/charles.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Fetch.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Fetch.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Heart.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "heart.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Power.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "power.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } -------------------------------------------------------------------------------- /CDN Fetch/CDN_Fetch.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | CDN_Fetch.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/BackButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Group.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/Settings.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Settings.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/StatusIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "CDNFetch~universal@1x.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template" 14 | } 15 | } -------------------------------------------------------------------------------- /CDN Fetch/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/18/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | autoreleasepool { 13 | let app = NSApplication.shared 14 | let delegate = AppDelegate() 15 | app.delegate = delegate 16 | app.run() 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /Pods/Target Support Files/STRegex/STRegex-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double RegexVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char RegexVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double AlamofireVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char AlamofireVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /CDN Fetch/CDN_Fetch.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /CDN Fetch/Helpers/Notification+Names.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notification+Names.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/23/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Notification.Name { 12 | 13 | // MARK: - Application notification names 14 | static let ItemsDidUpdate = Notification.Name(rawValue: "ItemsDidUpdate") 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_CDN_FetchVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_CDN_FetchVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_CDN_FetchTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_CDN_FetchTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CKNavigation/CKNavigation-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "CKNavigation.h" 14 | 15 | FOUNDATION_EXPORT double CKNavigationVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char CKNavigationVersionString[]; 17 | 18 | -------------------------------------------------------------------------------- /Pods/CKNavigation/Sources/CKNavigation.h: -------------------------------------------------------------------------------- 1 | // 2 | // CKNavigation.h 3 | // CKNavigation 4 | // 5 | // Created by Charles Kenney on 10/16/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for CKNavigation. 12 | FOUNDATION_EXPORT double CKNavigationVersionNumber; 13 | 14 | //! Project version string for CKNavigation. 15 | FOUNDATION_EXPORT const unsigned char CKNavigationVersionString[]; 16 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_CDN_FetchUITestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_CDN_FetchUITestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/STRegex/Source/ThreadLocal.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Convenience wrapper for generically storing values of type `T` in thread-local storage. 4 | internal final class ThreadLocal { 5 | let key: String 6 | 7 | init(_ key: String) { 8 | self.key = key 9 | } 10 | 11 | var value: T? { 12 | get { 13 | return Thread.current.threadDictionary[key] as? T 14 | } 15 | set { 16 | Thread.current.threadDictionary[key] = newValue 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (4.5.1) 3 | - CKNavigation (0.1.2) 4 | - STRegex (1.1.0) 5 | 6 | DEPENDENCIES: 7 | - Alamofire (~> 4.5) 8 | - CKNavigation (~> 0.1.2) 9 | - STRegex (~> 1.1) 10 | 11 | SPEC CHECKSUMS: 12 | Alamofire: 2d95912bf4c34f164fdfc335872e8c312acaea4a 13 | CKNavigation: 5a061c699a4fbeedf4f01e6f4363ca58f92a3bbd 14 | STRegex: eb1f4c2fe9e2f0265b8df8634774cd8cd8914018 15 | 16 | PODFILE CHECKSUM: 4d62e35c94f9d57e774b5cf0930144349ac5bdb4 17 | 18 | COCOAPODS: 1.3.1 19 | -------------------------------------------------------------------------------- /Pods/CKNavigation/Sources/CKNavigatableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CKNavigatable.swift 3 | // CKNavigation 4 | // 5 | // Created by Charles Kenney on 10/16/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | open class CKNavigatableViewController: NSViewController { 13 | 14 | public var navigationController: CKNavigationController? 15 | 16 | } 17 | 18 | extension CKNavigatableViewController: CKNavigatable { } 19 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (4.5.1) 3 | - CKNavigation (0.1.2) 4 | - STRegex (1.1.0) 5 | 6 | DEPENDENCIES: 7 | - Alamofire (~> 4.5) 8 | - CKNavigation (~> 0.1.2) 9 | - STRegex (~> 1.1) 10 | 11 | SPEC CHECKSUMS: 12 | Alamofire: 2d95912bf4c34f164fdfc335872e8c312acaea4a 13 | CKNavigation: 5a061c699a4fbeedf4f01e6f4363ca58f92a3bbd 14 | STRegex: eb1f4c2fe9e2f0265b8df8634774cd8cd8914018 15 | 16 | PODFILE CHECKSUM: 4d62e35c94f9d57e774b5cf0930144349ac5bdb4 17 | 18 | COCOAPODS: 1.3.1 19 | -------------------------------------------------------------------------------- /CDN Fetch/Helpers/String+Utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Utils.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/19/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Regex 11 | 12 | extension String { 13 | 14 | 15 | public func getFileExtension() -> String { 16 | let exp = Regex("\\..*$") 17 | let match = exp.firstMatch(in: self) 18 | return match?.matchedString ?? "" 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /CDN Fetch/Utils/LoginItemUtility.h: -------------------------------------------------------------------------------- 1 | // 2 | // LoginItemUtility.h 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/23/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | #ifndef LoginItemUtility_h 10 | #define LoginItemUtility_h 11 | 12 | #import 13 | #import 14 | 15 | @interface LoginItemUtility: NSObject 16 | 17 | + (void)addToLoginItems; 18 | + (void)deleteFromLoginItems; 19 | 20 | @end 21 | 22 | #endif /* LoginItemUtility_h */ 23 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.12' 2 | 3 | target 'CDN Fetch' do 4 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 5 | use_frameworks! 6 | 7 | # setup inherits 8 | 9 | target 'CDN FetchTests' do 10 | inherit! :search_paths 11 | # Pods for testing 12 | end 13 | 14 | target 'CDN FetchUITests' do 15 | inherit! :search_paths 16 | # Pods for testing 17 | end 18 | 19 | # Pods for CDN Fetch 20 | 21 | pod 'Alamofire', '~> 4.5' 22 | pod 'CKNavigation', '~> 0.1.2' 23 | pod 'STRegex', '~> 1.1' 24 | 25 | end 26 | -------------------------------------------------------------------------------- /Pods/STRegex/Source/Foundation+Ranges.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | #if !swift(>=3.2) && os(Linux) 4 | typealias NSTextCheckingResult = TextCheckingResult 5 | #endif 6 | 7 | internal extension NSTextCheckingResult { 8 | var ranges: [NSRange] { 9 | #if swift(>=4) || os(Linux) 10 | return stride(from: 0, to: numberOfRanges, by: 1).map(range) 11 | #else 12 | return stride(from: 0, to: numberOfRanges, by: 1).map(rangeAt) 13 | #endif 14 | } 15 | } 16 | 17 | internal extension String { 18 | var entireRange: NSRange { 19 | return NSRange(location: 0, length: utf16.count) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Pods/Target Support Files/STRegex/STRegex.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/STRegex 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/STRegex 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | -------------------------------------------------------------------------------- /Pods/CKNavigation/Sources/CKNavigatable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CKNavigatable.swift 3 | // CKNavigation 4 | // 5 | // Created by Charles Kenney on 10/16/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | public protocol CKNavigatable { 13 | 14 | var navigationController: CKNavigationController? { get set } 15 | 16 | } 17 | 18 | 19 | public extension CKNavigatable { 20 | 21 | mutating func setNavigationController(to navigationController: CKNavigationController) { 22 | self.navigationController = navigationController 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Alamofire 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CKNavigation/CKNavigation.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/CKNavigation 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/CKNavigation 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | SWIFT_VERSION = 4.0 13 | -------------------------------------------------------------------------------- /CDN Fetch/Helpers/NSWindow+CenterFrame.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSWindow+CenterFrame.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/20/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | extension NSWindow { 13 | 14 | public func centerFrameToScreen() { 15 | if let screenSize = screen?.frame.size { 16 | let centerX = (screenSize.width - self.frame.size.width) / 2 17 | let centerY = (screenSize.height - self.frame.size.height) / 2 18 | let center = NSPoint(x: centerX, y: centerY) 19 | self.setFrameOrigin(center) 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Pods/CKNavigation/Sources/Stack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Stack.swift 3 | // CKNavigation 4 | // 5 | // Created by Charles Kenney on 10/16/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | // MARK: - Stack Helper 13 | internal struct Stack { 14 | fileprivate var array = [T]() 15 | 16 | public var isEmpty: Bool { 17 | return array.isEmpty 18 | } 19 | 20 | public var count: Int { 21 | return array.count 22 | } 23 | 24 | public mutating func push(_ element: T) { 25 | array.append(element) 26 | } 27 | 28 | public mutating func pop() -> T? { 29 | return array.popLast() 30 | } 31 | 32 | public var top: T? { 33 | return array.last 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CDN FetchTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CDN FetchUITests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation" "$PODS_CONFIGURATION_BUILD_DIR/STRegex" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation/CKNavigation.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/STRegex/Regex.framework/Headers" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation" "$PODS_CONFIGURATION_BUILD_DIR/STRegex" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation/CKNavigation.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/STRegex/Regex.framework/Headers" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation" "$PODS_CONFIGURATION_BUILD_DIR/STRegex" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation/CKNavigation.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/STRegex/Regex.framework/Headers" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests.release.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation" "$PODS_CONFIGURATION_BUILD_DIR/STRegex" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation/CKNavigation.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/STRegex/Regex.framework/Headers" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /CDN Fetch/Models/AssetType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssetType.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/19/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @objc(AssetType) 12 | enum AssetType: Int16 { 13 | case javascript 14 | case css 15 | case map 16 | case generic 17 | 18 | public static func getExtensionFor(fileName: String) -> String { 19 | let ext = fileName.split(separator: ".").last ?? "" 20 | return String(ext) 21 | } 22 | 23 | public static func getFileType(forExtension ext: String) -> AssetType { 24 | switch (ext) { 25 | case "js", "jsx": 26 | return .javascript 27 | case "css": 28 | return .css 29 | case "map": 30 | return .map 31 | default: 32 | return .generic 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CDN Fetch/Helpers/NSUserInterfaceItem+Identifiers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSUserInterfaceIdentifiers+Identifiers.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/20/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | extension NSUserInterfaceItemIdentifier { 13 | 14 | static let assetColumn = NSUserInterfaceItemIdentifier(rawValue: "AssetColumn") 15 | 16 | static let resultColumn = NSUserInterfaceItemIdentifier(rawValue: "ResultColumn") 17 | 18 | static let assetRow = NSUserInterfaceItemIdentifier(rawValue: "AssetRow") 19 | 20 | static let favoriteColumn = NSUserInterfaceItemIdentifier(rawValue: "FavoriteColumn") 21 | 22 | static let resultRow = NSUserInterfaceItemIdentifier(rawValue: "ResultRow") 23 | 24 | static let favoriteRow = NSUserInterfaceItemIdentifier(rawValue: "FavoriteRow") 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/STRegex/Info.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.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Info.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 | 4.5.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CKNavigation/Info.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 | 0.1.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Info.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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Info.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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Info.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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CODE_SIGN_IDENTITY = 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation" "$PODS_CONFIGURATION_BUILD_DIR/STRegex" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation/CKNavigation.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/STRegex/Regex.framework/Headers" 7 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CKNavigation" -framework "Regex" 8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 9 | PODS_BUILD_DIR = $BUILD_DIR 10 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CODE_SIGN_IDENTITY = 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation" "$PODS_CONFIGURATION_BUILD_DIR/STRegex" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/CKNavigation/CKNavigation.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/STRegex/Regex.framework/Headers" 7 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CKNavigation" -framework "Regex" 8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 9 | PODS_BUILD_DIR = $BUILD_DIR 10 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | -------------------------------------------------------------------------------- /CDN Fetch/Windows/SettingsWindow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingWindow.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/20/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | class SettingsWindow: NSWindow { 13 | 14 | 15 | convenience init() { 16 | let rect = NSRect(x: 0, y: 0, width: 350, height: 325) 17 | self.init(contentRect: rect, styleMask: .closable, backing: .buffered, defer: false) 18 | self.isReleasedWhenClosed = false 19 | setupWindow() 20 | } 21 | 22 | 23 | func setupWindow() { 24 | self.centerFrameToScreen() 25 | self.appearance = NSAppearance(named: .vibrantDark) 26 | self.styleMask = [.titled, .closable, .miniaturizable] 27 | self.isOpaque = false 28 | self.isMovableByWindowBackground = true 29 | self.backgroundColor = NSColor(white: 0.2, alpha: 0.95) 30 | self.titlebarAppearsTransparent = true 31 | self.title = "CDN Fetch Settings" 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /CDN Fetch/CDN_Fetch.xcdatamodeld/CDN_Fetch.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /CDN Fetch/Models/FavoriteAsset.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FavoriteAsset.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/20/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | 12 | class FavoriteAsset: NSManagedObject { 13 | 14 | // return AssetType(rawValue: self.typeState) 15 | 16 | var type: AssetType? { 17 | get { 18 | return AssetType(rawValue: self.typeState) 19 | } 20 | set { 21 | if let newState = newValue?.rawValue { 22 | self.typeState = newState 23 | } 24 | } 25 | } 26 | 27 | } 28 | 29 | 30 | extension FavoriteAsset { 31 | 32 | @nonobjc public class func fetchRequest() -> NSFetchRequest { 33 | return NSFetchRequest(entityName: "FavoriteAsset") 34 | } 35 | 36 | @NSManaged public var library: String? 37 | @NSManaged public var name: String? 38 | @NSManaged public var typeState: Int16 39 | @NSManaged public var uri: String? 40 | @NSManaged public var version: String? 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /Pods/STRegex/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Adam Sharp 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2017 Charles Kenney 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pods/Alamofire/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Pods/CKNavigation/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2017 Charles Kenney 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /CDN Fetch.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CDN Fetch.xcscheme 8 | 9 | orderHint 10 | 6 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 56384C1F1F992D7A0009AF4F 16 | 17 | primary 18 | 19 | 20 | 56384C321F992D7B0009AF4F 21 | 22 | primary 23 | 24 | 25 | 56384C3D1F992D7B0009AF4F 26 | 27 | primary 28 | 29 | 30 | 5655F4231F9D5F3400BB9291 31 | 32 | primary 33 | 34 | 35 | 567EA9141F9D3E81004852CA 36 | 37 | primary 38 | 39 | 40 | 56ED0B8F1F9D412800A02C33 41 | 42 | primary 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /CDN Fetch/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LSApplicationCategoryType 6 | public.app-category.developer-tools 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0.0 23 | CFBundleVersion 24 | 1 25 | LSBackgroundOnly 26 | 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | LSUIElement 30 | 31 | NSHumanReadableCopyright 32 | Copyright © 2017 Charles Kenney. All rights reserved. 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /CDN FetchUITests/CDN_FetchUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CDN_FetchUITests.swift 3 | // CDN FetchUITests 4 | // 5 | // Created by Charles Kenney on 10/19/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class CDN_FetchUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Alamofire.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 0 13 | 14 | CDN FetchTests.xcscheme_^#shared#^_ 15 | 16 | orderHint 17 | 7 18 | 19 | CKNavigation.xcscheme 20 | 21 | isShown 22 | 23 | orderHint 24 | 1 25 | 26 | Pods-CDN Fetch.xcscheme 27 | 28 | isShown 29 | 30 | orderHint 31 | 2 32 | 33 | Pods-CDN FetchTests.xcscheme 34 | 35 | isShown 36 | 37 | orderHint 38 | 3 39 | 40 | Pods-CDN FetchUITests.xcscheme 41 | 42 | isShown 43 | 44 | orderHint 45 | 4 46 | 47 | STRegex.xcscheme 48 | 49 | isShown 50 | 51 | orderHint 52 | 5 53 | 54 | 55 | SuppressBuildableAutocreation 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /CDN Fetch/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /CDN FetchTests/AssetTypeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssetType.swift 3 | // CDN FetchTests 4 | // 5 | // Created by Charles Kenney on 10/20/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import CDN_Fetch 11 | 12 | class AssetTypeTests: XCTestCase { 13 | 14 | let sampleFiles = [ 15 | "bootstrap-materialize/styles/bootstrap-mat.min.css", 16 | "jquery.min.js", 17 | "jquery.map", 18 | "bootstrap.min.css", 19 | "file.bin", 20 | ] 21 | 22 | let sampleExtensions = [ 23 | "css", 24 | "css", 25 | "bin", 26 | "ttf", 27 | "map", 28 | "js", 29 | "html" 30 | ] 31 | 32 | override func setUp() { 33 | super.setUp() 34 | print("Start: `AssertType` Tests") 35 | } 36 | 37 | override func tearDown() { 38 | super.tearDown() 39 | } 40 | 41 | func testGetExtensionForFileName() { 42 | var results: [String] = [] 43 | let expected = [ 44 | "css", 45 | "js", 46 | "map", 47 | "css", 48 | "bin", 49 | ] 50 | for file in self.sampleFiles { 51 | results.append(AssetType.getExtensionFor(fileName: file)) 52 | } 53 | XCTAssert(expected == results) 54 | } 55 | 56 | func testGetFileTypeForExtension() { 57 | var results: [AssetType] = [] 58 | let expected: [AssetType] = [ 59 | .css, 60 | .css, 61 | .generic, 62 | .generic, 63 | .map, 64 | .javascript, 65 | .generic 66 | ] 67 | for ext in self.sampleExtensions { 68 | results.append(AssetType.getFileType(forExtension: ext)) 69 | } 70 | XCTAssert(expected == results) 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/DispatchQueue+Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DispatchQueue+Alamofire.swift 3 | // 4 | // Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Dispatch 26 | import Foundation 27 | 28 | extension DispatchQueue { 29 | static var userInteractive: DispatchQueue { return DispatchQueue.global(qos: .userInteractive) } 30 | static var userInitiated: DispatchQueue { return DispatchQueue.global(qos: .userInitiated) } 31 | static var utility: DispatchQueue { return DispatchQueue.global(qos: .utility) } 32 | static var background: DispatchQueue { return DispatchQueue.global(qos: .background) } 33 | 34 | func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) { 35 | asyncAfter(deadline: .now() + delay, execute: closure) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | banner 3 |

4 | 5 |

6 | 7 | build status 8 | 9 | 10 | swift-status 11 | 12 | 13 | license-status 14 | 15 | 16 | 17 | 18 |

19 | 20 |

21 | A mac status bar app to make fetching assets quick and simple. 22 |

23 |

24 | 25 | Download in the appstore 26 | 27 |

28 |
29 | 30 |

Fetching assets 📚

31 |

32 | fetch demo 33 |

34 |

Easily search for and link assets from your status bar. You don't even have to leave your text editor!

35 | 36 |
37 | 38 |

Pick your favorites ❤️

39 |

40 | favorites demo 41 |

42 |

Add your go-to assets to your favorites, and you don't even have to search for them.

43 | 44 |
45 | 46 |

Launch on startup 🚀

47 |

48 | startup demo 49 |

50 |

CDN Fetch is very low profile, which makes it very suitable for launching on startup.

51 | 52 |

License 📜

53 |

54 | © 2017 Charles Kenney 55 |

56 | -------------------------------------------------------------------------------- /Pods/STRegex/Source/Memo.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Rob Rix. All rights reserved. 2 | // 3 | // Source: https://github.com/robrix/Memo/blob/326153487940ab19c1d25761656269e25fbbf119/Memo/Memo.swift 4 | 5 | /// Deferred, memoized evaluation. 6 | internal struct Memo { 7 | // MARK: Lifecycle 8 | 9 | /// Constructs a `Memo` which lazily evaluates the argument. 10 | init(_ unevaluated: @escaping () -> T) { 11 | self.init(unevaluated: unevaluated) 12 | } 13 | 14 | /// Constructs a `Memo` which lazily evaluates the passed function. 15 | init(unevaluated: @escaping () -> T) { 16 | self.init(state: .unevaluated(unevaluated)) 17 | } 18 | 19 | /// Constructs a `Memo` wrapping the already-evaluated argument. 20 | init(evaluated: T) { 21 | self.init(state: .evaluated(evaluated)) 22 | } 23 | 24 | // MARK: Properties 25 | 26 | /// Returns the value held by the receiver, computing & memoizing it first if necessary. 27 | var value: T { 28 | return state.value.value() 29 | } 30 | 31 | // MARK: Private 32 | 33 | /// Initialize with the passed `state`. 34 | private init(state: MemoState) { 35 | self.state = MutableBox(state) 36 | } 37 | 38 | /// The underlying state. 39 | /// 40 | /// The `enum` implements the basic semantics (either evaluated or un), 41 | /// while the `MutableBox` provides us with reference semantics for the 42 | /// memoized result. 43 | private let state: MutableBox> 44 | } 45 | 46 | // MARK: Private 47 | 48 | /// Private state for memoization. 49 | private enum MemoState { 50 | case evaluated(T) 51 | case unevaluated(() -> T) 52 | 53 | /// Return the value, computing and memoizing it first if necessary. 54 | mutating func value() -> T { 55 | switch self { 56 | case let .evaluated(x): 57 | return x 58 | case let .unevaluated(f): 59 | let value = f() 60 | self = .evaluated(value) 61 | return value 62 | } 63 | } 64 | } 65 | 66 | /// A mutable reference type boxing a value. 67 | private final class MutableBox { 68 | init(_ value: T) { 69 | self.value = value 70 | } 71 | 72 | var value: T 73 | } 74 | -------------------------------------------------------------------------------- /CDN Fetch/Utils/LoginItemUtility.m: -------------------------------------------------------------------------------- 1 | // 2 | // LoginItemUtility.m 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/23/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | #import "LoginItemUtility.h" 10 | 11 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 12 | 13 | @implementation LoginItemUtility 14 | 15 | /** 16 | * Use LSSharedFileListRef is depreciated in favor of the 17 | * System Management framework, however LSSharedFileRef allows 18 | * the user to manage the login item in settings, without the 19 | * app. This is most preferable as it is more accessable to the user. 20 | */ 21 | 22 | // adds to shared login items 23 | + (void)addToLoginItems { 24 | LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 25 | NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; 26 | NSURL *bundleUrl = [NSURL fileURLWithPath:bundlePath]; 27 | 28 | if (list) { 29 | LSSharedFileListItemRef listItem = LSSharedFileListInsertItemURL(list, kLSSharedFileListItemLast, NULL, NULL, (__bridge CFURLRef)bundleUrl, NULL, NULL); 30 | if (listItem) { 31 | CFRelease(listItem); 32 | } 33 | CFRelease(list); 34 | NSLog(@"Successfully added login item"); 35 | } else { 36 | NSLog(@"Error adding login item"); 37 | } 38 | } 39 | 40 | // deletes from shared login items 41 | + (void)deleteFromLoginItems { 42 | LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 43 | NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; 44 | 45 | if (list) { 46 | UInt32 val; 47 | NSArray *listArray = CFBridgingRelease(LSSharedFileListCopySnapshot(list, &val)); 48 | 49 | for (id file in listArray) { 50 | LSSharedFileListItemRef fileRef = (__bridge LSSharedFileListItemRef)file; 51 | CFURLRef bundleUrl = LSSharedFileListItemCopyResolvedURL(fileRef, 0, NULL); 52 | 53 | if (bundleUrl) { 54 | NSString *resolved = [(__bridge NSURL*)bundleUrl path]; 55 | 56 | if ([resolved compare:bundlePath] == NSOrderedSame) { 57 | LSSharedFileListItemRemove(list, fileRef); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/Alamofire.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/CKNavigation.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /CDN Fetch/Views/NavigationHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationHeader.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/19/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | class NavigationHeader: NSView { 13 | 14 | let backButton: NSButton = { 15 | let btn = NSButton(image: #imageLiteral(resourceName: "BackButton"), target: nil, action: nil) 16 | btn.isBordered = false 17 | btn.translatesAutoresizingMaskIntoConstraints = false 18 | return btn 19 | }() 20 | 21 | 22 | let headingLabel: NSTextField = { 23 | let label = NSTextField() 24 | label.alignment = .center 25 | label.isBezeled = false 26 | label.isEditable = false 27 | label.isBordered = false 28 | label.font = NSFont(name: "Helvetica Neue Thin", size: 18) 29 | label.translatesAutoresizingMaskIntoConstraints = false 30 | return label 31 | }() 32 | 33 | override func draw(_ dirtyRect: NSRect) { 34 | super.draw(dirtyRect) 35 | setupView() 36 | addViews() 37 | setupBackButton() 38 | setupHeadingLabel() 39 | } 40 | 41 | 42 | func setupView() { 43 | self.wantsLayer = true 44 | self.layer!.backgroundColor = .clear 45 | } 46 | 47 | 48 | func addViews() { 49 | self.addSubview(backButton) 50 | self.addSubview(headingLabel) 51 | } 52 | 53 | 54 | // Add back button constraints 55 | func setupBackButton() { 56 | backButton.heightAnchor.constraint(equalToConstant: 20).isActive = true 57 | backButton.widthAnchor.constraint(equalToConstant: 35).isActive = true 58 | backButton.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true 59 | backButton.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 5).isActive = true 60 | } 61 | 62 | 63 | // Add name label constraints 64 | func setupHeadingLabel() { 65 | headingLabel.heightAnchor.constraint(equalToConstant: 30).isActive = true 66 | headingLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true 67 | headingLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 55).isActive = true 68 | headingLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -55).isActive = true 69 | } 70 | 71 | 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcshareddata/xcschemes/CDN FetchTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | 50 | 51 | 52 | 53 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/Notifications.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notifications.swift 3 | // 4 | // Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | extension Notification.Name { 28 | /// Used as a namespace for all `URLSessionTask` related notifications. 29 | public struct Task { 30 | /// Posted when a `URLSessionTask` is resumed. The notification `object` contains the resumed `URLSessionTask`. 31 | public static let DidResume = Notification.Name(rawValue: "org.alamofire.notification.name.task.didResume") 32 | 33 | /// Posted when a `URLSessionTask` is suspended. The notification `object` contains the suspended `URLSessionTask`. 34 | public static let DidSuspend = Notification.Name(rawValue: "org.alamofire.notification.name.task.didSuspend") 35 | 36 | /// Posted when a `URLSessionTask` is cancelled. The notification `object` contains the cancelled `URLSessionTask`. 37 | public static let DidCancel = Notification.Name(rawValue: "org.alamofire.notification.name.task.didCancel") 38 | 39 | /// Posted when a `URLSessionTask` is completed. The notification `object` contains the completed `URLSessionTask`. 40 | public static let DidComplete = Notification.Name(rawValue: "org.alamofire.notification.name.task.didComplete") 41 | } 42 | } 43 | 44 | // MARK: - 45 | 46 | extension Notification { 47 | /// Used as a namespace for all `Notification` user info dictionary keys. 48 | public struct Key { 49 | /// User info dictionary key representing the `URLSessionTask` associated with the notification. 50 | public static let Task = "org.alamofire.notification.key.task" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/STRegex.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/Pods-CDN Fetch.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/Pods-CDN FetchTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/Pods-CDN FetchUITests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Pods/STRegex/Source/Options.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// `Options` defines alternate behaviours of regular expressions when matching. 4 | public struct Options: OptionSet { 5 | 6 | /// Ignores the case of letters when matching. 7 | /// 8 | /// Example: 9 | /// 10 | /// let a = Regex("a", options: .ignoreCase) 11 | /// a.allMatches(in: "aA").map { $0.matchedString } // ["a", "A"] 12 | public static let ignoreCase = Options(rawValue: 1) 13 | 14 | /// Ignore any metacharacters in the pattern, treating every character as 15 | /// a literal. 16 | /// 17 | /// Example: 18 | /// 19 | /// let parens = Regex("()", options: .ignoreMetacharacters) 20 | /// parens.matches("()") // true 21 | public static let ignoreMetacharacters = Options(rawValue: 1 << 1) 22 | 23 | /// By default, "^" matches the beginning of the string and "$" matches the 24 | /// end of the string, ignoring any newlines. With this option, "^" will 25 | /// the beginning of each line, and "$" will match the end of each line. 26 | /// 27 | /// let foo = Regex("^foo", options: .anchorsMatchLines) 28 | /// foo.allMatches(in: "foo\nbar\nfoo\n").count // 2 29 | public static let anchorsMatchLines = Options(rawValue: 1 << 2) 30 | 31 | /// Usually, "." matches all characters except newlines (\n). Using this 32 | /// this options will allow "." to match newLines 33 | /// 34 | /// let newLines = Regex("test.test", options: .dotMatchesLineSeparators) 35 | /// newLines.allMatches(in: "test\ntest").count // 1 36 | public static let dotMatchesLineSeparators = Options(rawValue: 1 << 3) 37 | 38 | // MARK: OptionSetType 39 | 40 | public let rawValue: Int 41 | 42 | public init(rawValue: Int) { 43 | self.rawValue = rawValue 44 | } 45 | 46 | } 47 | 48 | internal extension Options { 49 | 50 | /// Transform an instance of `Regex.Options` into the equivalent `NSRegularExpression.Options`. 51 | /// 52 | /// - returns: The equivalent `NSRegularExpression.Options`. 53 | func toNSRegularExpressionOptions() -> NSRegularExpression.Options { 54 | var options = NSRegularExpression.Options() 55 | if contains(.ignoreCase) { options.insert(.caseInsensitive) } 56 | if contains(.ignoreMetacharacters) { options.insert(.ignoreMetacharacters) } 57 | if contains(.anchorsMatchLines) { options.insert(.anchorsMatchLines) } 58 | if contains(.dotMatchesLineSeparators) { options.insert(.dotMatchesLineSeparators) } 59 | return options 60 | } 61 | 62 | } 63 | 64 | // MARK: Deprecations / Removals 65 | 66 | extension Options { 67 | 68 | @available(*, unavailable, renamed: "ignoreCase") 69 | public static var IgnoreCase: Options { 70 | fatalError() 71 | } 72 | 73 | @available(*, unavailable, renamed: "ignoreMetacharacters") 74 | public static var IgnoreMetacharacters: Options { 75 | fatalError() 76 | } 77 | 78 | @available(*, unavailable, renamed: "anchorsMatchLines") 79 | public static var AnchorsMatchLines: Options { 80 | fatalError() 81 | } 82 | 83 | @available(*, unavailable, renamed: "dotMatchesLineSeparators") 84 | public static var DotMatchesLineSeparators: Options { 85 | fatalError() 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Alamofire 5 | 6 | Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | 27 | ## CKNavigation 28 | 29 | The MIT License 30 | 31 | Copyright (c) 2017 Charles Kenney 32 | 33 | Permission is hereby granted, free of charge, to any person obtaining a copy 34 | of this software and associated documentation files (the "Software"), to deal 35 | in the Software without restriction, including without limitation the rights 36 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 37 | copies of the Software, and to permit persons to whom the Software is 38 | furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in 41 | all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 44 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 45 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 46 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 47 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 48 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 49 | THE SOFTWARE. 50 | 51 | 52 | ## STRegex 53 | 54 | The MIT License (MIT) 55 | 56 | Copyright (c) 2015 Adam Sharp 57 | 58 | Permission is hereby granted, free of charge, to any person obtaining a copy 59 | of this software and associated documentation files (the "Software"), to deal 60 | in the Software without restriction, including without limitation the rights 61 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 62 | copies of the Software, and to permit persons to whom the Software is 63 | furnished to do so, subject to the following conditions: 64 | 65 | The above copyright notice and this permission notice shall be included in all 66 | copies or substantial portions of the Software. 67 | 68 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 69 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 70 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 71 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 72 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 73 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 74 | SOFTWARE. 75 | 76 | Generated by CocoaPods - https://cocoapods.org 77 | -------------------------------------------------------------------------------- /Pods/CKNavigation/README.md: -------------------------------------------------------------------------------- 1 |

CKNavigationController

2 |

3 | A UINavigationController port for Cocoa development 4 |

5 | 6 |

7 | 8 |

9 | 10 |

Including CKNavigation

11 |

12 | To integrate CKNavigation into your Xcode project using CocoaPods, specify it in your Podfile: 13 |

14 | 15 | ```ruby 16 | source 'https://github.com/CocoaPods/Specs.git' 17 | platform :osx, '10.12' 18 | 19 | target 'TargetName' do 20 | pod 'CKNavigation', '~> 0.1.1' 21 | end 22 | ``` 23 | 24 |

Usage

25 |

26 | The CKNavigationController is meant to provide navigation in a single NSWindow similar to that of UIKit's UINavigationController on iOS. This is a great solution for seperating views in low profile status bar apps and the like. 27 |

28 |

29 | Implementing a CKNavigationController is exactly like UINavigationController in iOS. Simply call the initializer and pass in the controller you'd like to set as root. Note: in order to add a view controller to a navigation controller, the view controller must subclass CKNavigatableViewController or explicitly conform to the CKNavigatable protocol. 30 |

31 | 32 | ```swift 33 | import CKNavigation 34 | 35 | let myController = MyViewController() 36 | let myNavigationController = CKNavigationController(rootViewController: myController) 37 | ``` 38 | 39 |

40 | This approach is well suited for programmatic user interfaces. You could simply create an NSWindow instance, and add your navigation controller as a subview. 41 |

42 | 43 | ```swift 44 | import Foundation 45 | import Cocoa 46 | import CKNavigation 47 | 48 | class AppDelegate: NSObject, NSApplicationDelegate { 49 | 50 | var navigationController: CKNavigationController! 51 | 52 | let controller = ViewController() 53 | 54 | let window: NSWindow { 55 | let content = NSRect(x: 0, y: 0, width: 500, height: 500) 56 | let window = NSWindow(contentRect: content, styleMask: .closable, backing: .buffered, defer: false) 57 | return window 58 | }() 59 | 60 | func applicationDidFinishLaunching(_ aNotification: Notification) { 61 | // initialize navigation controller with root view 62 | navigationController = CKNavigationController(rootViewController: controller) 63 | // add navigation controller to the window 64 | window.contentView?.addSubview(navigationController.view) 65 | navigationController.view.wantsLayer = true 66 | window.makeKeyAndOrderFront(nil) 67 | } 68 | } 69 | ``` 70 | 71 |

72 | Pushing a view controller to the stack is done easily, too. From inside the myViewController class: 73 |

74 | 75 | ```swift 76 | @objc func handleNextButtonPress(_ sender: Any?) { 77 | let newController = AnotherViewController() 78 | self.navigationController!.pushViewController(newController) 79 | } 80 | ``` 81 | 82 |

83 | Similarly, to pop a view controller from the stack: 84 |

85 | 86 | ```swift 87 | @objc func handlePreviousButtonPress(_ sender: Any?) { 88 | self.navigationController!.popViewController() 89 | } 90 | ``` 91 | 92 |

Example

93 |

94 | The example that you see in the demo gif, at the top is available here. This implementation was 100% programmatic. 95 |

96 | 97 |

License

98 |

99 | MIT © Charles Kenney 100 |

-------------------------------------------------------------------------------- /Pods/STRegex/README.md: -------------------------------------------------------------------------------- 1 | # Regex 2 | 3 | Pattern match like a boss. 4 | 5 | 6 | 7 | ## Usage 8 | 9 | Create: 10 | 11 | ```swift 12 | // Use `Regex.init(_:)` to build a regex from a static pattern 13 | 14 | let greeting = Regex("hello (world|universe)") 15 | 16 | // Use `Regex.init(string:)` to construct a regex from dynamic data, and 17 | // gracefully handle invalid input 18 | 19 | var validations: [String: Regex] 20 | 21 | for (name, pattern) in config.loadValidations() { 22 | do { 23 | validations[name] = try Regex(string: pattern) 24 | } catch { 25 | print("error building validation \(name): \(error)") 26 | } 27 | } 28 | ``` 29 | 30 | Match: 31 | 32 | ```swift 33 | if greeting.matches("hello universe!") { 34 | print("wow, you're friendly!") 35 | } 36 | ``` 37 | 38 | _Pattern_ match: 39 | 40 | ```swift 41 | switch someTextFromTheInternet { 42 | case Regex("DROP DATABASE (.+)"): 43 | // TODO: patch security hole 44 | default: 45 | break 46 | } 47 | ``` 48 | 49 | Capture: 50 | 51 | ```swift 52 | let greeting = Regex("hello (world|universe|swift)") 53 | 54 | if let subject = greeting.firstMatch(in: "hello swift")?.captures[0] { 55 | print("ohai \(subject)") 56 | } 57 | ``` 58 | 59 | Find and replace: 60 | 61 | ```swift 62 | "hello world".replacingFirst(matching: "h(ello) (\\w+)", with: "H$1, $2!") 63 | // "Hello, world!" 64 | ``` 65 | 66 | Accessing the last match: 67 | 68 | ```swift 69 | switch text { 70 | case Regex("hello (\\w+)"): 71 | if let friend = Regex.lastMatch?.captures[0] { 72 | print("lovely to meet you, \(friend)!") 73 | } 74 | case Regex("goodbye (\\w+)"): 75 | if let traitor = Regex.lastMatch?.captures[0] { 76 | print("so sorry to see you go, \(traitor)!") 77 | } 78 | default: 79 | break 80 | } 81 | ``` 82 | 83 | Options: 84 | 85 | ```swift 86 | let totallyUniqueExamples = Regex("^(hello|foo).*$", options: [.IgnoreCase, .AnchorsMatchLines]) 87 | let multilineText = "hello world\ngoodbye world\nFOOBAR\n" 88 | let matchingLines = totallyUniqueExamples.allMatches(in: multilineText).map { $0.matchedString } 89 | // ["hello world", "FOOBAR"] 90 | ``` 91 | 92 | 93 | 94 | ## Installation 95 | 96 | #### Swift Package Manager 97 | 98 | Add a dependency to your `Package.swift`: 99 | 100 | ```swift 101 | // Swift 4 102 | 103 | let package = Package( 104 | name: "MyPackage", 105 | dependencies: [ 106 | // other dependencies... 107 | .package(url: "https://github.com/sharplet/Regex.git", from: "1.0.0"), 108 | ] 109 | ) 110 | ``` 111 | 112 | ```swift 113 | // Swift 3 114 | 115 | let package = Package( 116 | name: "MyPackage", 117 | dependencies: [ 118 | // other dependencies... 119 | .Package(url: "https://github.com/sharplet/Regex.git", majorVersion: 1), 120 | ] 121 | ) 122 | ``` 123 | 124 | #### Carthage 125 | 126 | Put this in your Cartfile: 127 | 128 | ``` 129 | github "sharplet/Regex" ~> 1.0 130 | ``` 131 | 132 | #### CocoaPods 133 | 134 | Put this in your Podfile: 135 | 136 | ```ruby 137 | pod "STRegex", "~> 1.0" 138 | ``` 139 | 140 | 141 | 142 | ## Contributing 143 | 144 | See [CONTRIBUTING.md](CONTRIBUTING.md). 145 | 146 | 147 | 148 | ## Development Setup 149 | 150 | ### Swift Package Manager 151 | 152 | Build and run the tests: 153 | 154 | ``` 155 | export SWIFT_PACKAGE_TEST_REGEX=true 156 | swift test 157 | 158 | # or just 159 | 160 | rake test:package 161 | ``` 162 | 163 | If you're on a Mac, testing on Linux is supported via [Docker for Mac](https://www.docker.com/docker-mac). 164 | Once Docker is set up, start a Linux shell: 165 | 166 | ``` 167 | rake docker 168 | ``` 169 | 170 | And run the tests via Swift Package Manager. 171 | 172 | ### Carthage & Xcode 173 | 174 | Install Carthage via Homebrew and build the dependencies: 175 | 176 | ``` 177 | brew install carthage 178 | rake setup 179 | ``` 180 | 181 | `xcpretty` is recommended, for prettifying test output: 182 | 183 | ``` 184 | gem install xcpretty 185 | ``` 186 | 187 | Then run the tests: 188 | 189 | ``` 190 | # one of 191 | rake test:osx 192 | rake test:ios 193 | rake test:tvos 194 | ``` 195 | 196 | ### Linting 197 | 198 | Regex uses [SwiftLint](https://github.com/realm/SwiftLint) to validate code style. 199 | SwiftLint is automatically run against pull requests using [Hound CI](https://houndci.com/). 200 | 201 | You can also run it locally: 202 | 203 | ``` 204 | $ brew install swiftlint 205 | $ rake swiftlint 206 | ``` 207 | 208 | 209 | 210 | ## License 211 | 212 | See [LICENSE.txt](LICENSE.txt). 213 | -------------------------------------------------------------------------------- /CDN Fetch/Views/ResultCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResultCell.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/18/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | class ResultCell: NSTableCellView { 13 | 14 | var nameText: String? { 15 | didSet { 16 | if let text = nameText { 17 | self.nameLabel.stringValue = text 18 | } 19 | } 20 | } 21 | 22 | var descriptionText: String? { 23 | didSet { 24 | if let text = descriptionText { 25 | self.descriptionLabel.stringValue = text 26 | } 27 | } 28 | } 29 | 30 | var licenseText: String? { 31 | didSet { 32 | if let text = licenseText { 33 | self.licenseLabel.stringValue = text 34 | } 35 | } 36 | } 37 | 38 | let nameLabel: NSTextField = { 39 | let label = NSTextField(string: "") 40 | label.font = NSFont(name: "Helvetica Neue Thin", size: 20) 41 | label.backgroundColor = .clear 42 | label.textColor = .white 43 | label.isBordered = false 44 | label.isEditable = false 45 | label.translatesAutoresizingMaskIntoConstraints = false 46 | return label 47 | }() 48 | 49 | let licenseLabel: NSTextField = { 50 | let label = NSTextField(string: "") 51 | label.font = NSFont(name: "Helvetica Neue", size: 14) 52 | label.backgroundColor = .clear 53 | label.alignment = .center 54 | label.textColor = .white 55 | label.isBezeled = false 56 | label.isBordered = false 57 | label.isEditable = false 58 | label.translatesAutoresizingMaskIntoConstraints = false 59 | return label 60 | }() 61 | 62 | let descriptionLabel: NSTextField = { 63 | let label = NSTextField(string: "") 64 | label.font = NSFont(name: "Helvetica Neue", size: 12) 65 | label.backgroundColor = .clear 66 | label.textColor = .white 67 | label.usesSingleLineMode = false 68 | label.cell!.isScrollable = false 69 | label.cell!.wraps = true 70 | label.lineBreakMode = .byWordWrapping 71 | label.isBezeled = false 72 | label.isBordered = false 73 | label.isEditable = false 74 | label.allowsDefaultTighteningForTruncation = true 75 | label.translatesAutoresizingMaskIntoConstraints = false 76 | return label 77 | }() 78 | 79 | override func draw(_ dirtyRect: NSRect) { 80 | super.draw(dirtyRect) 81 | addViews() 82 | setupView() 83 | setupNameLabel() 84 | setupLicenseLabel() 85 | setupDescriptionLabel() 86 | } 87 | 88 | func setupView() { 89 | self.wantsLayer = true 90 | self.layer?.backgroundColor = NSColor(red:40/255.0, green:40/255.0, blue:40/255.0, alpha: 1).cgColor 91 | } 92 | 93 | func addViews() { 94 | self.addSubview(nameLabel) 95 | self.addSubview(licenseLabel) 96 | self.addSubview(descriptionLabel) 97 | } 98 | 99 | func setupNameLabel() { 100 | nameLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 5).isActive = true 101 | nameLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true 102 | nameLabel.heightAnchor.constraint(equalToConstant: 23).isActive = true 103 | nameLabel.widthAnchor.constraint(equalTo: self.widthAnchor, constant: -110).isActive = true 104 | } 105 | 106 | func setupLicenseLabel() { 107 | licenseLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 5).isActive = true 108 | licenseLabel.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true 109 | licenseLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true 110 | licenseLabel.widthAnchor.constraint(equalToConstant: 90).isActive = true 111 | } 112 | 113 | func setupDescriptionLabel() { 114 | descriptionLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 10).isActive = true 115 | descriptionLabel.heightAnchor.constraint(equalTo: self.heightAnchor, constant: -43).isActive = true 116 | descriptionLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true 117 | descriptionLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10).isActive = true 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /Pods/STRegex/Source/MatchResult.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A `MatchResult` encapsulates the result of a single match in a string, 4 | /// providing access to the matched string, as well as any capture groups within 5 | /// that string. 6 | public struct MatchResult { 7 | 8 | // MARK: Accessing match results 9 | 10 | /// The entire matched string. 11 | /// 12 | /// Example: 13 | /// 14 | /// let pattern = Regex("a*") 15 | /// 16 | /// if let match = pattern.firstMatch(in: "aaa") { 17 | /// match.matchedString // "aaa" 18 | /// } 19 | /// 20 | /// if let match = pattern.firstMatch(in: "bbb") { 21 | /// match.matchedString // "" 22 | /// } 23 | public var matchedString: String { 24 | return _result.matchedString 25 | } 26 | 27 | /// The range of the matched string. 28 | public var range: Range { 29 | return _string.range(from: _result.range) 30 | } 31 | 32 | /// The matching string for each capture group in the regular expression 33 | /// (if any). 34 | /// 35 | /// **Note:** Usually if the match was successful, the captures will by 36 | /// definition be non-nil. However if a given capture group is optional, the 37 | /// captured string may also be nil, depending on the particular string that 38 | /// is being matched against. 39 | /// 40 | /// Example: 41 | /// 42 | /// let regex = Regex("(a)?(b)") 43 | /// 44 | /// regex.firstMatch(in: "ab")?.captures // [Optional("a"), Optional("b")] 45 | /// regex.firstMatch(in: "b")?.captures // [nil, Optional("b")] 46 | public var captures: [String?] { 47 | return _result.captures 48 | } 49 | 50 | /// The ranges of each capture (if any). 51 | /// 52 | /// - seealso: The discussion and example for `MatchResult.captures`. 53 | public var captureRanges: [Range?] { 54 | return _captureRanges.value 55 | } 56 | 57 | // MARK: Internal initialisers 58 | 59 | internal var matchResult: NSTextCheckingResult { 60 | return _result.result 61 | } 62 | 63 | private let _captureRanges: Memo<[Range?]> 64 | private let _result: _MatchResult 65 | private let _string: String 66 | 67 | internal init(_ string: String, _ result: NSTextCheckingResult) { 68 | self._result = _MatchResult(string, result) 69 | self._string = string 70 | self._captureRanges = Memo { [_result] in 71 | _result.captureRanges.map { utf16range in 72 | utf16range.map { string.range(from: $0) } 73 | } 74 | } 75 | } 76 | 77 | } 78 | 79 | private extension String { 80 | func range(from utf16Range: Range) -> Range { 81 | #if swift(>=4.0) 82 | return utf16Range 83 | #else 84 | let start = Index(utf16Range.lowerBound, within: self)! 85 | let end = Index(utf16Range.upperBound, within: self)! 86 | return start..=4.0) 95 | private let string: String 96 | #else 97 | private let string: String.UTF16View 98 | #endif 99 | fileprivate let result: NSTextCheckingResult 100 | 101 | fileprivate init(_ string: String, _ result: NSTextCheckingResult) { 102 | #if swift(>=4.0) 103 | self.string = string 104 | #else 105 | self.string = string.utf16 106 | #endif 107 | self.result = result 108 | } 109 | 110 | lazy var range: Range = { 111 | return self.utf16Range(from: self.result.range)! 112 | }() 113 | 114 | lazy var captures: [String?] = { 115 | return self.captureRanges.map { $0.map(self.substring(from:)) } 116 | }() 117 | 118 | lazy var captureRanges: [Range?] = { 119 | return self.result.ranges.dropFirst().map(self.utf16Range(from:)) 120 | }() 121 | 122 | lazy var matchedString: String = { 123 | let range = self.utf16Range(from: self.result.range)! 124 | return self.substring(from: range) 125 | }() 126 | 127 | private func utf16Range(from range: NSRange) -> Range? { 128 | #if swift(>=4.0) 129 | return Range(range, in: string) 130 | #else 131 | guard range.location != NSNotFound else { return nil } 132 | let start = string.index(string.startIndex, offsetBy: range.location) 133 | let end = string.index(start, offsetBy: range.length) 134 | return start..) -> String { 139 | return String(describing: string[range]) 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /CDN Fetch.xcodeproj/xcuserdata/charles.xcuserdatad/xcschemes/CDN Fetch.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 44 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 76 | 78 | 84 | 85 | 86 | 87 | 88 | 89 | 95 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 104 | wait 105 | fi 106 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 104 | wait 105 | fi 106 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/) 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | Alamofire 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | The MIT License 47 | 48 | Copyright (c) 2017 Charles Kenney <me@charleskenney.com> 49 | 50 | Permission is hereby granted, free of charge, to any person obtaining a copy 51 | of this software and associated documentation files (the "Software"), to deal 52 | in the Software without restriction, including without limitation the rights 53 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 54 | copies of the Software, and to permit persons to whom the Software is 55 | furnished to do so, subject to the following conditions: 56 | 57 | The above copyright notice and this permission notice shall be included in 58 | all copies or substantial portions of the Software. 59 | 60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 61 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 62 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 63 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 64 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 65 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 66 | THE SOFTWARE. 67 | 68 | License 69 | MIT 70 | Title 71 | CKNavigation 72 | Type 73 | PSGroupSpecifier 74 | 75 | 76 | FooterText 77 | The MIT License (MIT) 78 | 79 | Copyright (c) 2015 Adam Sharp 80 | 81 | Permission is hereby granted, free of charge, to any person obtaining a copy 82 | of this software and associated documentation files (the "Software"), to deal 83 | in the Software without restriction, including without limitation the rights 84 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 85 | copies of the Software, and to permit persons to whom the Software is 86 | furnished to do so, subject to the following conditions: 87 | 88 | The above copyright notice and this permission notice shall be included in all 89 | copies or substantial portions of the Software. 90 | 91 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 92 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 93 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 94 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 95 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 96 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 97 | SOFTWARE. 98 | 99 | License 100 | LICENSE.txt 101 | Title 102 | STRegex 103 | Type 104 | PSGroupSpecifier 105 | 106 | 107 | FooterText 108 | Generated by CocoaPods - https://cocoapods.org 109 | Title 110 | 111 | Type 112 | PSGroupSpecifier 113 | 114 | 115 | StringsTable 116 | Acknowledgements 117 | Title 118 | Acknowledgements 119 | 120 | 121 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | 104 | if [[ "$CONFIGURATION" == "Debug" ]]; then 105 | install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework" 106 | install_framework "${BUILT_PRODUCTS_DIR}/CKNavigation/CKNavigation.framework" 107 | install_framework "${BUILT_PRODUCTS_DIR}/STRegex/Regex.framework" 108 | fi 109 | if [[ "$CONFIGURATION" == "Release" ]]; then 110 | install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework" 111 | install_framework "${BUILT_PRODUCTS_DIR}/CKNavigation/CKNavigation.framework" 112 | install_framework "${BUILT_PRODUCTS_DIR}/STRegex/Regex.framework" 113 | fi 114 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 115 | wait 116 | fi 117 | -------------------------------------------------------------------------------- /CDN Fetch/Controllers/FavoritesController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FavoritesController.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/18/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CKNavigation 11 | import Cocoa 12 | 13 | class FavoritesController: CKNavigatableViewController { 14 | 15 | 16 | var favorites: [FavoriteAsset] = [] { 17 | didSet { 18 | favoritesTable.reloadData() 19 | } 20 | } 21 | 22 | 23 | let header: NavigationHeader = { 24 | let header = NavigationHeader() 25 | header.headingLabel.stringValue = "Favorites" 26 | header.translatesAutoresizingMaskIntoConstraints = false 27 | return header 28 | }() 29 | 30 | 31 | let scrollView: NSScrollView = { 32 | let scroll = NSScrollView() 33 | scroll.wantsLayer = false 34 | scroll.backgroundColor = .clear 35 | scroll.translatesAutoresizingMaskIntoConstraints = false 36 | return scroll 37 | }() 38 | 39 | 40 | let favoritesTable: NSTableView = { 41 | let table = NSTableView() 42 | table.rowHeight = 50 43 | table.wantsLayer = false 44 | table.headerView = nil 45 | table.backgroundColor = .clear 46 | table.translatesAutoresizingMaskIntoConstraints = false 47 | return table 48 | }() 49 | 50 | 51 | let column: NSTableColumn = { 52 | let col = NSTableColumn() 53 | col.identifier = .assetColumn 54 | return col 55 | }() 56 | 57 | 58 | override func loadView() { 59 | self.view = NSView() 60 | } 61 | 62 | 63 | override func viewDidLoad() { 64 | super.viewDidLoad() 65 | setupView() 66 | addViews() 67 | setupHeader() 68 | setupFavoritesTable() 69 | fetchFavorites() 70 | observeAssetChanges() 71 | } 72 | 73 | 74 | func setupView() { 75 | self.view.translatesAutoresizingMaskIntoConstraints = false 76 | self.view.widthAnchor.constraint(equalToConstant: 350).isActive = true 77 | self.view.heightAnchor.constraint(equalToConstant: 500).isActive = true 78 | self.view.wantsLayer = true 79 | } 80 | 81 | 82 | func addViews() { 83 | self.view.addSubview(header) 84 | self.view.addSubview(scrollView) 85 | } 86 | 87 | 88 | func setupHeader() { 89 | header.backButton.target = self 90 | header.backButton.action = #selector(goBack(_:)) 91 | header.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true 92 | header.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true 93 | header.heightAnchor.constraint(equalToConstant: 50).isActive = true 94 | } 95 | 96 | 97 | // MARK: - Setup table and add constraints 98 | func setupFavoritesTable() { 99 | favoritesTable.addTableColumn(column) 100 | favoritesTable.delegate = self 101 | favoritesTable.dataSource = self 102 | scrollView.documentView = favoritesTable 103 | scrollView.contentView.drawsBackground = false 104 | scrollView.hasVerticalScroller = true 105 | scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50).isActive = true 106 | scrollView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true 107 | scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true 108 | } 109 | 110 | 111 | func observeAssetChanges() { 112 | NotificationCenter.default.addObserver(self, selector: #selector(reloadData(_:)), name: .ItemsDidUpdate, object: nil) 113 | } 114 | 115 | 116 | } 117 | 118 | 119 | 120 | // MARK: - Table View 121 | extension FavoritesController: NSTableViewDelegate, NSTableViewDataSource { 122 | 123 | 124 | func numberOfRows(in tableView: NSTableView) -> Int { 125 | return favorites.count 126 | } 127 | 128 | 129 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 130 | // get favorite item 131 | let item = favorites[row] 132 | // create cell 133 | let cell = FavoriteCell() 134 | cell.identifier = .assetRow 135 | cell.asset = item 136 | return cell 137 | } 138 | 139 | 140 | func selectionShouldChange(in tableView: NSTableView) -> Bool { 141 | return false 142 | } 143 | 144 | 145 | } 146 | 147 | 148 | 149 | // MARK: - Core Data calls 150 | extension FavoritesController { 151 | 152 | 153 | func fetchFavorites() { 154 | guard let delegate = NSApplication.shared.delegate as? AppDelegate else { 155 | print("could not get delegate") 156 | return 157 | } 158 | 159 | let context = delegate.persistentContainer.viewContext 160 | 161 | do { 162 | favorites = try context.fetch(FavoriteAsset.fetchRequest()) 163 | } catch let error { 164 | print("error getting favorites: \(error)") 165 | } 166 | } 167 | 168 | 169 | } 170 | 171 | 172 | 173 | // MARK: - Actions 174 | extension FavoritesController { 175 | 176 | 177 | @objc func goBack(_ sender: Any?) { 178 | self.navigationController?.popViewController() 179 | } 180 | 181 | 182 | @objc func reloadData(_ sender: Any?) { 183 | fetchFavorites() 184 | } 185 | 186 | } 187 | -------------------------------------------------------------------------------- /CDN Fetch/Controllers/SettingsController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsController.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/18/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | import ServiceManagement 12 | 13 | class SettingsController: NSViewController { 14 | 15 | 16 | let launchOnStartupKey = "LAUNCH_ON_STARTUP" 17 | 18 | 19 | let logo: NSImageView = { 20 | let img = NSImageView() 21 | img.image = #imageLiteral(resourceName: "LogoBanner") 22 | img.translatesAutoresizingMaskIntoConstraints = false 23 | return img 24 | }() 25 | 26 | let copyrightLabel: NSTextField = { 27 | let label = NSTextField() 28 | label.font = NSFont(name: "Helvetica Neue Thin", size: 15) 29 | label.isBezeled = false 30 | label.isBordered = false 31 | label.isEditable = false 32 | label.alignment = .center 33 | label.backgroundColor = .clear 34 | label.stringValue = "\u{00A9} 2017 Charles Kenney" 35 | label.translatesAutoresizingMaskIntoConstraints = false 36 | return label 37 | }() 38 | 39 | 40 | let viewSourceButton: NSButton = { 41 | let button = NSButton(title: "view source", target: nil, action: nil) 42 | button.translatesAutoresizingMaskIntoConstraints = false 43 | return button 44 | }() 45 | 46 | 47 | let launchOnStartupButton: NSButton = { 48 | let button = NSButton(checkboxWithTitle: "launch on startup", target: nil, action: nil) 49 | button.alignment = .center 50 | button.translatesAutoresizingMaskIntoConstraints = false 51 | return button 52 | }() 53 | 54 | 55 | override func loadView() { 56 | self.view = NSView() 57 | } 58 | 59 | override func viewDidLoad() { 60 | super.viewDidLoad() 61 | setupView() 62 | addViews() 63 | setupLogo() 64 | setupCopyrightLabel() 65 | setupViewSourceButton() 66 | setupLaunchOnStartupButton() 67 | } 68 | 69 | 70 | func getInitialLaunchState() -> Bool { 71 | let defaults = UserDefaults.standard 72 | let launchOnStartupState = defaults.value(forKey: launchOnStartupKey) as? Bool ?? false 73 | return launchOnStartupState 74 | } 75 | 76 | 77 | func setupView() { 78 | } 79 | 80 | 81 | func addViews() { 82 | self.view.addSubview(logo) 83 | self.view.addSubview(copyrightLabel) 84 | self.view.addSubview(viewSourceButton) 85 | self.view.addSubview(launchOnStartupButton) 86 | } 87 | 88 | 89 | func setupLogo() { 90 | logo.heightAnchor.constraint(equalToConstant: 120).isActive = true 91 | logo.widthAnchor.constraint(equalToConstant: 200).isActive = true 92 | logo.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50).isActive = true 93 | logo.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true 94 | } 95 | 96 | 97 | func setupCopyrightLabel() { 98 | copyrightLabel.heightAnchor.constraint(equalToConstant: 23).isActive = true 99 | copyrightLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true 100 | copyrightLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true 101 | copyrightLabel.topAnchor.constraint(equalTo: logo.bottomAnchor, constant: 10).isActive = true 102 | } 103 | 104 | 105 | func setupViewSourceButton() { 106 | viewSourceButton.target = self 107 | viewSourceButton.action = #selector(viewSource(_:)) 108 | viewSourceButton.heightAnchor.constraint(equalToConstant: 30).isActive = true 109 | viewSourceButton.widthAnchor.constraint(equalToConstant: 100).isActive = true 110 | viewSourceButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true 111 | viewSourceButton.topAnchor.constraint(equalTo: copyrightLabel.bottomAnchor, constant: 5).isActive = true 112 | } 113 | 114 | 115 | func setupLaunchOnStartupButton() { 116 | launchOnStartupButton.state = getInitialLaunchState() ? .on : .off 117 | launchOnStartupButton.target = self 118 | launchOnStartupButton.action = #selector(changeLaunchOnStartup(_:)) 119 | launchOnStartupButton.heightAnchor.constraint(equalToConstant: 30).isActive = true 120 | launchOnStartupButton.widthAnchor.constraint(equalToConstant: 150).isActive = true 121 | launchOnStartupButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true 122 | launchOnStartupButton.topAnchor.constraint(equalTo: viewSourceButton.bottomAnchor, constant: 20).isActive = true 123 | } 124 | 125 | 126 | } 127 | 128 | 129 | 130 | // MARK: - Actions 131 | extension SettingsController { 132 | 133 | 134 | @objc func viewSource(_ sender: Any?) { 135 | 136 | let url = URL(string: "https://github.com/charliekenney23/cdn-fetch")! 137 | NSWorkspace.shared.open(url) 138 | } 139 | 140 | 141 | @objc func changeLaunchOnStartup(_ sender: NSButton) { 142 | let state = sender.state.rawValue == 1 ? true : false 143 | let defaults = UserDefaults.standard 144 | // try to set login item preference 145 | if (state) { 146 | LoginItemUtility.addToLoginItems() 147 | } else { 148 | LoginItemUtility.deleteFromLoginItems() 149 | } 150 | defaults.setValue(state, forKey: launchOnStartupKey) 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN Fetch/Pods-CDN Fetch-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchTests/Pods-CDN FetchTests-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CDN FetchUITests/Pods-CDN FetchUITests-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /CDN Fetch/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/19/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import CKNavigation 11 | 12 | class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate { 13 | 14 | 15 | var navigationController: CKNavigationController! 16 | 17 | let mainController = MainController() 18 | 19 | let settingsController = SettingsController() 20 | 21 | lazy var settingsWindow = SettingsWindow() 22 | 23 | 24 | let statusItem: NSStatusItem = { 25 | let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) 26 | item.image = #imageLiteral(resourceName: "StatusIcon") 27 | return item 28 | }() 29 | 30 | 31 | let popover = NSPopover() 32 | 33 | 34 | func applicationDidFinishLaunching(_ aNotification: Notification) { 35 | setupPopover() 36 | setupSettings() 37 | } 38 | 39 | 40 | 41 | // MARK: - Core Data stack 42 | lazy var persistentContainer: NSPersistentContainer = { 43 | 44 | let container = NSPersistentContainer(name: "CDN_Fetch") 45 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in 46 | if let error = error { 47 | 48 | fatalError("Unresolved error \(error)") 49 | } 50 | }) 51 | return container 52 | }() 53 | 54 | // MARK: - Core Data Saving and Undo support 55 | @IBAction func saveAction(_ sender: AnyObject?) { 56 | 57 | let context = persistentContainer.viewContext 58 | 59 | if !context.commitEditing() { 60 | NSLog("\(NSStringFromClass(type(of: self))) unable to commit editing before saving") 61 | } 62 | if context.hasChanges { 63 | do { 64 | try context.save() 65 | } catch { 66 | 67 | let nserror = error as NSError 68 | NSApplication.shared.presentError(nserror) 69 | } 70 | } 71 | } 72 | 73 | func windowWillReturnUndoManager(window: NSWindow) -> UndoManager? { 74 | 75 | return persistentContainer.viewContext.undoManager 76 | } 77 | 78 | func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { 79 | 80 | let context = persistentContainer.viewContext 81 | 82 | if !context.commitEditing() { 83 | NSLog("\(NSStringFromClass(type(of: self))) unable to commit editing to terminate") 84 | return .terminateCancel 85 | } 86 | 87 | if !context.hasChanges { 88 | return .terminateNow 89 | } 90 | 91 | do { 92 | try context.save() 93 | } catch { 94 | let nserror = error as NSError 95 | 96 | let result = sender.presentError(nserror) 97 | if (result) { 98 | return .terminateCancel 99 | } 100 | 101 | let question = NSLocalizedString("Could not save changes while quitting. Quit anyway?", comment: "Quit without saves error question message") 102 | let info = NSLocalizedString("Quitting now will lose any changes you have made since the last successful save", comment: "Quit without saves error question info"); 103 | let quitButton = NSLocalizedString("Quit anyway", comment: "Quit anyway button title") 104 | let cancelButton = NSLocalizedString("Cancel", comment: "Cancel button title") 105 | let alert = NSAlert() 106 | alert.messageText = question 107 | alert.informativeText = info 108 | alert.addButton(withTitle: quitButton) 109 | alert.addButton(withTitle: cancelButton) 110 | 111 | let answer = alert.runModal() 112 | if answer == .alertSecondButtonReturn { 113 | return .terminateCancel 114 | } 115 | } 116 | return .terminateNow 117 | } 118 | 119 | } 120 | 121 | 122 | 123 | // MARK: - Setup 124 | extension AppDelegate { 125 | 126 | 127 | func setupPopover() { 128 | popover.appearance = NSAppearance.init(named: .vibrantDark) 129 | popover.delegate = self 130 | navigationController = CKNavigationController(rootViewController: mainController) 131 | popover.contentViewController = navigationController 132 | popover.contentSize = NSSize(width: 350, height: 500) 133 | popover.setAccessibilityFrontmost(true) 134 | statusItem.action = #selector(togglePopover(_:)) 135 | } 136 | 137 | func setupSettings() { 138 | settingsWindow.isOpaque = false 139 | settingsWindow.contentView = settingsController.view 140 | } 141 | 142 | 143 | } 144 | 145 | 146 | 147 | // MARK: - Actions 148 | extension AppDelegate { 149 | 150 | 151 | func launchSettings() { 152 | settingsWindow.makeKeyAndOrderFront(nil) 153 | } 154 | 155 | 156 | @objc func togglePopover(_ sender: Any?) { 157 | if (popover.isShown) { 158 | popover.close() 159 | } else { 160 | statusItem.button!.highlight(true) 161 | popover.show(relativeTo: NSZeroRect, of: statusItem.button!, preferredEdge: NSRectEdge.minY) 162 | } 163 | } 164 | 165 | 166 | func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { 167 | print("it worked") 168 | if let window = sender.windows.first { 169 | if flag { 170 | window.orderFront(nil) 171 | } else { 172 | window.makeKeyAndOrderFront(nil) 173 | } 174 | } 175 | return true 176 | } 177 | 178 | 179 | 180 | } 181 | 182 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/Timeline.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Timeline.swift 3 | // 4 | // Copyright (c) 2014-2017 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// Responsible for computing the timing metrics for the complete lifecycle of a `Request`. 28 | public struct Timeline { 29 | /// The time the request was initialized. 30 | public let requestStartTime: CFAbsoluteTime 31 | 32 | /// The time the first bytes were received from or sent to the server. 33 | public let initialResponseTime: CFAbsoluteTime 34 | 35 | /// The time when the request was completed. 36 | public let requestCompletedTime: CFAbsoluteTime 37 | 38 | /// The time when the response serialization was completed. 39 | public let serializationCompletedTime: CFAbsoluteTime 40 | 41 | /// The time interval in seconds from the time the request started to the initial response from the server. 42 | public let latency: TimeInterval 43 | 44 | /// The time interval in seconds from the time the request started to the time the request completed. 45 | public let requestDuration: TimeInterval 46 | 47 | /// The time interval in seconds from the time the request completed to the time response serialization completed. 48 | public let serializationDuration: TimeInterval 49 | 50 | /// The time interval in seconds from the time the request started to the time response serialization completed. 51 | public let totalDuration: TimeInterval 52 | 53 | /// Creates a new `Timeline` instance with the specified request times. 54 | /// 55 | /// - parameter requestStartTime: The time the request was initialized. Defaults to `0.0`. 56 | /// - parameter initialResponseTime: The time the first bytes were received from or sent to the server. 57 | /// Defaults to `0.0`. 58 | /// - parameter requestCompletedTime: The time when the request was completed. Defaults to `0.0`. 59 | /// - parameter serializationCompletedTime: The time when the response serialization was completed. Defaults 60 | /// to `0.0`. 61 | /// 62 | /// - returns: The new `Timeline` instance. 63 | public init( 64 | requestStartTime: CFAbsoluteTime = 0.0, 65 | initialResponseTime: CFAbsoluteTime = 0.0, 66 | requestCompletedTime: CFAbsoluteTime = 0.0, 67 | serializationCompletedTime: CFAbsoluteTime = 0.0) 68 | { 69 | self.requestStartTime = requestStartTime 70 | self.initialResponseTime = initialResponseTime 71 | self.requestCompletedTime = requestCompletedTime 72 | self.serializationCompletedTime = serializationCompletedTime 73 | 74 | self.latency = initialResponseTime - requestStartTime 75 | self.requestDuration = requestCompletedTime - requestStartTime 76 | self.serializationDuration = serializationCompletedTime - requestCompletedTime 77 | self.totalDuration = serializationCompletedTime - requestStartTime 78 | } 79 | } 80 | 81 | // MARK: - CustomStringConvertible 82 | 83 | extension Timeline: CustomStringConvertible { 84 | /// The textual representation used when written to an output stream, which includes the latency, the request 85 | /// duration and the total duration. 86 | public var description: String { 87 | let latency = String(format: "%.3f", self.latency) 88 | let requestDuration = String(format: "%.3f", self.requestDuration) 89 | let serializationDuration = String(format: "%.3f", self.serializationDuration) 90 | let totalDuration = String(format: "%.3f", self.totalDuration) 91 | 92 | // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is 93 | // fixed, we should move back to string interpolation by reverting commit 7d4a43b1. 94 | let timings = [ 95 | "\"Latency\": " + latency + " secs", 96 | "\"Request Duration\": " + requestDuration + " secs", 97 | "\"Serialization Duration\": " + serializationDuration + " secs", 98 | "\"Total Duration\": " + totalDuration + " secs" 99 | ] 100 | 101 | return "Timeline: { " + timings.joined(separator: ", ") + " }" 102 | } 103 | } 104 | 105 | // MARK: - CustomDebugStringConvertible 106 | 107 | extension Timeline: CustomDebugStringConvertible { 108 | /// The textual representation used when written to an output stream, which includes the request start time, the 109 | /// initial response time, the request completed time, the serialization completed time, the latency, the request 110 | /// duration and the total duration. 111 | public var debugDescription: String { 112 | let requestStartTime = String(format: "%.3f", self.requestStartTime) 113 | let initialResponseTime = String(format: "%.3f", self.initialResponseTime) 114 | let requestCompletedTime = String(format: "%.3f", self.requestCompletedTime) 115 | let serializationCompletedTime = String(format: "%.3f", self.serializationCompletedTime) 116 | let latency = String(format: "%.3f", self.latency) 117 | let requestDuration = String(format: "%.3f", self.requestDuration) 118 | let serializationDuration = String(format: "%.3f", self.serializationDuration) 119 | let totalDuration = String(format: "%.3f", self.totalDuration) 120 | 121 | // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is 122 | // fixed, we should move back to string interpolation by reverting commit 7d4a43b1. 123 | let timings = [ 124 | "\"Request Start Time\": " + requestStartTime, 125 | "\"Initial Response Time\": " + initialResponseTime, 126 | "\"Request Completed Time\": " + requestCompletedTime, 127 | "\"Serialization Completed Time\": " + serializationCompletedTime, 128 | "\"Latency\": " + latency + " secs", 129 | "\"Request Duration\": " + requestDuration + " secs", 130 | "\"Serialization Duration\": " + serializationDuration + " secs", 131 | "\"Total Duration\": " + totalDuration + " secs" 132 | ] 133 | 134 | return "Timeline: { " + timings.joined(separator: ", ") + " }" 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Pods/CKNavigation/Sources/CKNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CKNavigationController.swift 3 | // CKNavigation 4 | // 5 | // Created by Charles Kenney on 10/14/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreGraphics 11 | import Cocoa 12 | 13 | 14 | /** 15 | Type for `NSViewController` instances that conform to the `Navigatable` protocol. 16 | Navigatable Controllers can be pushed and popped from `CKNavigationController.rootViewController` 17 | */ 18 | public typealias NavigatableViewController = NSViewController & CKNavigatable 19 | 20 | 21 | /** 22 | Type for `Stack` of `NavigatableViewController`s 23 | */ 24 | internal typealias NavigatableViewControllerStack = Stack 25 | 26 | 27 | /** 28 | A controller that manages a stack of `NavigatableViewController`s, loaded from a nib or storyboard. 29 | Initialized with a single root view controller of type: `NavigatableViewController`. 30 | View controllers can be dynamically pushed and popped from the stack, but the root *will* always remain. 31 | @todo: Add animation and integrate `CKNavigationBar` 32 | @todo: Add `CKNavigationBar` and customization 33 | */ 34 | open class CKNavigationController: NSViewController, NSWindowDelegate { 35 | 36 | /** 37 | The container view that holds the `topViewController`. 38 | */ 39 | var container = NSView() 40 | 41 | 42 | /** 43 | The view controller that is currently key and visible. 44 | */ 45 | private var topViewController: NavigatableViewController? { 46 | didSet { 47 | // setup top view controller 48 | if let tvc = topViewController { 49 | setupController(controller: tvc) 50 | } 51 | } 52 | } 53 | 54 | 55 | /** 56 | The stack of view controllers pushed and popped from the root view controller. 57 | */ 58 | private var viewControllerStack = NavigatableViewControllerStack() 59 | 60 | 61 | open override func viewDidLoad() { 62 | super.viewDidLoad() 63 | // setup container 64 | print("test2") 65 | setupContainer() 66 | } 67 | 68 | 69 | open override func loadView() { 70 | // setup view 71 | self.view = NSView() 72 | print("loaded navigation view") 73 | } 74 | 75 | 76 | /** 77 | Pushes an instance of `NavigatableViewController` to the `viewControllerStack` 78 | - parameters: 79 | - controller: The view controller to push to the navigation stack 80 | */ 81 | open func pushViewController(_ controller: NavigatableViewController) { 82 | NSAnimationContext.beginGrouping() 83 | NSAnimationContext.current.completionHandler = { 84 | // push to stack 85 | self.viewControllerStack.push(controller) 86 | // add child view controller 87 | self.addChildViewController(controller) 88 | // update current view controller 89 | self.topViewController = self.viewControllerStack.top 90 | } 91 | NSAnimationContext.current.duration = 0.3 92 | NSAnimationContext.current.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) 93 | var origin = self.topViewController!.view.frame.origin 94 | origin.x -= 1000 95 | self.topViewController!.view.animator().setFrameOrigin(origin) 96 | NSAnimationContext.endGrouping() 97 | } 98 | 99 | 100 | /** 101 | Pops the `topViewController` off the `viewControllerStack` 102 | @todo: Allow custom animation 103 | */ 104 | open func popViewController() { 105 | if (viewControllerStack.count > 1) { 106 | NSAnimationContext.beginGrouping() 107 | NSAnimationContext.current.completionHandler = { 108 | // pop from stack 109 | _ = self.viewControllerStack.pop() 110 | // set previous view controller 111 | self.topViewController = self.viewControllerStack.top 112 | } 113 | NSAnimationContext.current.duration = 0.3 114 | NSAnimationContext.current.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 115 | var origin = self.topViewController!.view.frame.origin 116 | origin.x += 1000 117 | self.topViewController!.view.animator().setFrameOrigin(origin) 118 | NSAnimationContext.endGrouping() 119 | } 120 | } 121 | 122 | 123 | /** 124 | Pops all the view controllers in the `viewControllerStack` until the root view controller 125 | is surfaced. 126 | */ 127 | public func popToRootViewController() { 128 | while (viewControllerStack.count > 1) { 129 | popViewController() 130 | } 131 | } 132 | 133 | 134 | /** 135 | Sets up constraints for the container view 136 | */ 137 | open func setupContainer() { 138 | // add to view controller 139 | self.view.addSubview(container) 140 | // setup constraints 141 | container.translatesAutoresizingMaskIntoConstraints = false 142 | container.fitView(to: self.view) 143 | } 144 | 145 | 146 | /** 147 | Prepares controller for setting as `topViewController` 148 | - parameters: 149 | - controller: Controller to prepare 150 | */ 151 | private func setupController(controller: NavigatableViewController) { 152 | // remove all current views 153 | for subview in self.container.subviews { 154 | subview.removeFromSuperview() 155 | } 156 | // add root view controller to subview 157 | container.addSubview(controller.view) 158 | controller.view.translatesAutoresizingMaskIntoConstraints = false 159 | controller.view.fitView(to: container) 160 | var ptr = controller 161 | ptr.setNavigationController(to: self) 162 | } 163 | 164 | public convenience init(rootViewController controller: NavigatableViewController) { 165 | self.init() 166 | setRootViewController(controller) 167 | } 168 | 169 | /** 170 | A helper method for setting the root view controller 171 | - parameters: 172 | - controller: Controller to set as root 173 | */ 174 | public func setRootViewController(_ controller: NavigatableViewController) { 175 | // push to stack 176 | viewControllerStack.push(controller) 177 | // update top view 178 | topViewController = controller 179 | } 180 | 181 | 182 | } 183 | 184 | 185 | // MARK: - NSView Helpers 186 | fileprivate extension NSView { 187 | 188 | 189 | /** 190 | Fits a child view to the exact frame of a parent view 191 | - parameters: 192 | - parent: The superview to constrain to 193 | */ 194 | func fitView(to parent: NSView) { 195 | self.topAnchor.constraint(equalTo: parent.topAnchor).isActive = true 196 | self.rightAnchor.constraint(equalTo: parent.rightAnchor).isActive = true 197 | self.bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true 198 | self.leftAnchor.constraint(equalTo: parent.leftAnchor).isActive = true 199 | self.heightAnchor.constraint(equalTo: parent.heightAnchor).isActive = true 200 | self.widthAnchor.constraint(equalTo: parent.widthAnchor).isActive = true 201 | } 202 | 203 | 204 | } 205 | -------------------------------------------------------------------------------- /CDN Fetch/Controllers/AssetsController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssetsController.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/18/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | import CKNavigation 12 | import Alamofire 13 | 14 | 15 | class AssetsController: CKNavigatableViewController { 16 | 17 | 18 | var library: String? { 19 | didSet { 20 | assetsTable.reloadData() 21 | } 22 | } 23 | 24 | 25 | var version: String? { 26 | didSet { 27 | assetsTable.reloadData() 28 | } 29 | } 30 | 31 | 32 | var versions: [String]? { 33 | didSet { 34 | // TODO: add to versions menu 35 | print("got versions") 36 | } 37 | } 38 | 39 | 40 | var assets: Dictionary? { 41 | didSet { 42 | assetsTable.reloadData() 43 | } 44 | } 45 | 46 | 47 | let header: NavigationHeader = { 48 | let header = NavigationHeader() 49 | header.translatesAutoresizingMaskIntoConstraints = false 50 | return header 51 | }() 52 | 53 | 54 | let scrollView: NSScrollView = { 55 | let scroll = NSScrollView() 56 | scroll.wantsLayer = false 57 | scroll.backgroundColor = .clear 58 | scroll.translatesAutoresizingMaskIntoConstraints = false 59 | return scroll 60 | }() 61 | 62 | 63 | let assetsTable: NSTableView = { 64 | let table = NSTableView() 65 | table.rowHeight = 40 66 | table.wantsLayer = false 67 | table.headerView = nil 68 | table.backgroundColor = .clear 69 | table.translatesAutoresizingMaskIntoConstraints = false 70 | return table 71 | }() 72 | 73 | 74 | let column: NSTableColumn = { 75 | let col = NSTableColumn() 76 | col.identifier = .assetColumn 77 | return col 78 | }() 79 | 80 | 81 | convenience init(library: String) { 82 | self.init(nibName: nil, bundle: nil) 83 | self.library = library 84 | fetchAssets(for: library) 85 | } 86 | 87 | 88 | override func loadView() { 89 | self.view = NSView() 90 | } 91 | 92 | 93 | override func viewDidLoad() { 94 | super.viewDidLoad() 95 | setupView() 96 | addViews() 97 | setupHeader() 98 | setupAssetsTable() 99 | } 100 | 101 | 102 | func setupView() { 103 | self.view.translatesAutoresizingMaskIntoConstraints = false 104 | self.view.widthAnchor.constraint(equalToConstant: 350).isActive = true 105 | self.view.heightAnchor.constraint(equalToConstant: 500).isActive = true 106 | self.view.wantsLayer = true 107 | } 108 | 109 | 110 | // MARK: - Add subviews 111 | func addViews() { 112 | self.view.addSubview(scrollView) 113 | self.view.addSubview(header) 114 | } 115 | 116 | 117 | // MARK: - Setup header and add constraints 118 | func setupHeader() { 119 | header.backButton.target = self 120 | header.backButton.action = #selector(goBack(_:)) 121 | header.headingLabel.stringValue = library ?? "" 122 | header.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true 123 | header.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true 124 | header.heightAnchor.constraint(equalToConstant: 50).isActive = true 125 | } 126 | 127 | 128 | // MARK: - Setup table and add constraints 129 | func setupAssetsTable() { 130 | assetsTable.addTableColumn(column) 131 | assetsTable.delegate = self 132 | assetsTable.dataSource = self 133 | scrollView.documentView = assetsTable 134 | scrollView.contentView.drawsBackground = false 135 | scrollView.hasVerticalScroller = true 136 | scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50).isActive = true 137 | scrollView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true 138 | scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true 139 | } 140 | 141 | 142 | } 143 | 144 | 145 | 146 | // MARK: - Networking Tasks 147 | extension AssetsController { 148 | 149 | 150 | // Fetch assets for the current library 151 | func fetchAssets(for library: String) { 152 | // make request 153 | Alamofire.request("https://api.cdnjs.com/libraries/\(library)").responseJSON { res in 154 | 155 | guard let data = res.result.value as? [String:Any?] else { 156 | return print("no data") 157 | } 158 | 159 | guard let assetsData = data["assets"] as? Array> else { 160 | return print("no assets") 161 | } 162 | 163 | var versions: [String] = [] 164 | var assets: [String:Any?] = [:] 165 | 166 | // break up data in a consumable format 167 | // access assets by their corresponding versions 168 | for asset in assetsData { 169 | // format version to corresponding assets for controller 170 | guard let version = asset["version"] as? String, 171 | let files = asset["files"] as? [String] else { 172 | print("no version/files") 173 | continue 174 | } 175 | versions.append(version) 176 | assets[version] = files 177 | } 178 | 179 | // get latest version 180 | if let latestVersion = data["version"] as? String { 181 | self.version = latestVersion 182 | } else { 183 | self.version = versions.first ?? "" 184 | } 185 | 186 | self.assets = assets 187 | self.versions = versions 188 | } 189 | } 190 | 191 | 192 | } 193 | 194 | 195 | 196 | // MARK: - Table View Delegate 197 | extension AssetsController: NSTableViewDelegate, NSTableViewDataSource { 198 | 199 | 200 | // Set the table rows 201 | func numberOfRows(in tableView: NSTableView) -> Int { 202 | let currVersion = version ?? "" 203 | let currAssets = assets?[currVersion] as? [String] ?? [] 204 | return currAssets.count 205 | } 206 | 207 | 208 | // Render asset cell rows 209 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 210 | // Get library info 211 | let currVersion = version ?? "" 212 | let currAssets = assets?[currVersion] as? [String] ?? [] 213 | let currAsset = currAssets[row] 214 | // Creat row 215 | let cell = AssetCell() 216 | cell.identifier = .assetRow 217 | cell.assetName = currAsset 218 | cell.library = library ?? "" 219 | cell.version = version ?? "" 220 | cell.fetchButton.tag = row 221 | return cell 222 | } 223 | 224 | 225 | func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool { 226 | return false 227 | } 228 | 229 | 230 | } 231 | 232 | 233 | 234 | // MARK: - Navigatable 235 | extension AssetsController { 236 | 237 | 238 | @objc func goBack(_ sender: Any?) { 239 | self.navigationController!.popViewController() 240 | } 241 | 242 | } 243 | -------------------------------------------------------------------------------- /Pods/STRegex/Source/Regex.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Regex: CustomStringConvertible, CustomDebugStringConvertible { 4 | 5 | // MARK: Initialisation 6 | 7 | internal let regularExpression: NSRegularExpression 8 | 9 | /// Create a `Regex` based on a pattern string. 10 | /// 11 | /// If `pattern` is not a valid regular expression, an error is thrown 12 | /// describing the failure. 13 | /// 14 | /// - parameters: 15 | /// - pattern: A pattern string describing the regex. 16 | /// - options: Configure regular expression matching options. 17 | /// For details, see `Regex.Options`. 18 | /// 19 | /// - throws: A value of `ErrorType` describing the invalid regular expression. 20 | public init(string pattern: String, options: Options = []) throws { 21 | regularExpression = try NSRegularExpression( 22 | pattern: pattern, 23 | options: options.toNSRegularExpressionOptions()) 24 | } 25 | 26 | /// Create a `Regex` based on a static pattern string. 27 | /// 28 | /// Unlike `Regex.init(string:)` this initialiser is not failable. If `pattern` 29 | /// is an invalid regular expression, it is considered programmer error rather 30 | /// than a recoverable runtime error, so this initialiser instead raises a 31 | /// precondition failure. 32 | /// 33 | /// - requires: `pattern` is a valid regular expression. 34 | /// 35 | /// - parameters: 36 | /// - pattern: A pattern string describing the regex. 37 | /// - options: Configure regular expression matching options. 38 | /// For details, see `Regex.Options`. 39 | public init(_ pattern: StaticString, options: Options = []) { 40 | do { 41 | regularExpression = try NSRegularExpression( 42 | pattern: pattern.description, 43 | options: options.toNSRegularExpressionOptions()) 44 | } catch { 45 | preconditionFailure("unexpected error creating regex: \(error)") 46 | } 47 | } 48 | 49 | // MARK: Matching 50 | 51 | /// Returns `true` if the regex matches `string`, otherwise returns `false`. 52 | /// 53 | /// - parameter string: The string to test. 54 | /// 55 | /// - returns: `true` if the regular expression matches, otherwise `false`. 56 | /// 57 | /// - note: If the match is successful, `Regex.lastMatch` will be set with the 58 | /// result of the match. 59 | public func matches(_ string: String) -> Bool { 60 | return firstMatch(in: string) != nil 61 | } 62 | 63 | /// If the regex matches `string`, returns a `MatchResult` describing the 64 | /// first matched string and any captures. If there are no matches, returns 65 | /// `nil`. 66 | /// 67 | /// - parameter string: The string to match against. 68 | /// 69 | /// - returns: An optional `MatchResult` describing the first match, or `nil`. 70 | /// 71 | /// - note: If the match is successful, the result is also stored in `Regex.lastMatch`. 72 | public func firstMatch(in string: String) -> MatchResult? { 73 | let match = regularExpression 74 | .firstMatch(in: string, options: [], range: string.entireRange) 75 | .map { MatchResult(string, $0) } 76 | Regex._lastMatch = match 77 | return match 78 | } 79 | 80 | /// If the regex matches `string`, returns an array of `MatchResult`, describing 81 | /// every match inside `string`. If there are no matches, returns an empty 82 | /// array. 83 | /// 84 | /// - parameter string: The string to match against. 85 | /// 86 | /// - returns: An array of `MatchResult` describing every match in `string`. 87 | /// 88 | /// - note: If there is at least one match, the first is stored in `Regex.lastMatch`. 89 | public func allMatches(in string: String) -> [MatchResult] { 90 | let matches = regularExpression 91 | .matches(in: string, options: [], range: string.entireRange) 92 | .map { MatchResult(string, $0) } 93 | if let firstMatch = matches.first { Regex._lastMatch = firstMatch } 94 | return matches 95 | } 96 | 97 | // MARK: Accessing the last match 98 | 99 | /// After any match, the result will be stored in this property for later use. 100 | /// This is useful when pattern matching: 101 | /// 102 | /// switch "hello" { 103 | /// case Regex("l+"): 104 | /// let count = Regex.lastMatch!.matchedString.characters.count 105 | /// print("matched \(count) characters") 106 | /// default: 107 | /// break 108 | /// } 109 | /// 110 | /// This property uses thread-local storage, and thus is thread safe. 111 | public static var lastMatch: MatchResult? { 112 | return _lastMatch 113 | } 114 | 115 | private static let _lastMatchKey = "me.sharplet.Regex.lastMatch" 116 | 117 | private static var _lastMatch: MatchResult? { 118 | get { return ThreadLocal(_lastMatchKey).value } 119 | set { ThreadLocal(_lastMatchKey).value = newValue } 120 | } 121 | 122 | // MARK: Describing 123 | 124 | public var description: String { 125 | return regularExpression.pattern 126 | } 127 | 128 | public var debugDescription: String { 129 | return "/\(description)/" 130 | } 131 | 132 | } 133 | 134 | // MARK: Pattern matching 135 | 136 | /// Match `regex` on the left with some `string` on the right. Equivalent to 137 | /// `regex.matches(string)`, and allows for the use of a `Regex` in pattern 138 | /// matching contexts, e.g.: 139 | /// 140 | /// switch Regex("hello (\\w+)") { 141 | /// case "hello world": 142 | /// // successful match 143 | /// } 144 | /// 145 | /// - parameters: 146 | /// - regex: The regular expression to match against. 147 | /// - string: The string to test. 148 | /// 149 | /// - returns: `true` if the regular expression matches, otherwise `false`. 150 | public func ~= (regex: Regex, string: String) -> Bool { 151 | return regex.matches(string) 152 | } 153 | 154 | /// Match `string` on the left with some `regex` on the right. Equivalent to 155 | /// `regex.matches(string)`, and allows for the use of a `Regex` in pattern 156 | /// matching contexts, e.g.: 157 | /// 158 | /// switch "hello world" { 159 | /// case Regex("hello (\\w+)"): 160 | /// // successful match 161 | /// } 162 | /// 163 | /// - parameters: 164 | /// - regex: The regular expression to match against. 165 | /// - string: The string to test. 166 | /// 167 | /// - returns: `true` if the regular expression matches, otherwise `false`. 168 | public func ~= (string: String, regex: Regex) -> Bool { 169 | return regex.matches(string) 170 | } 171 | 172 | // MARK: Conformances 173 | 174 | extension Regex: Equatable { 175 | 176 | public static func == (lhs: Regex, rhs: Regex) -> Bool { 177 | return lhs.regularExpression == rhs.regularExpression 178 | } 179 | 180 | } 181 | 182 | extension Regex: Hashable { 183 | 184 | public var hashValue: Int { 185 | return regularExpression.hashValue 186 | } 187 | 188 | } 189 | 190 | #if swift(>=3.2) 191 | extension Regex: Codable { 192 | 193 | public init(from decoder: Decoder) throws { 194 | let string = try decoder.singleValueContainer().decode(String.self) 195 | try self.init(string: string) 196 | } 197 | 198 | public func encode(to encoder: Encoder) throws { 199 | var container = encoder.singleValueContainer() 200 | try container.encode(regularExpression.pattern) 201 | } 202 | 203 | } 204 | #endif 205 | 206 | // MARK: Deprecations / Removals 207 | 208 | extension Regex { 209 | 210 | @available(*, unavailable, renamed: "firstMatch(in:)") 211 | public func match(_ string: String) -> MatchResult? { 212 | fatalError() 213 | } 214 | 215 | @available(*, unavailable, renamed: "allMatches(in:)") 216 | public func allMatches(_ string: String) -> [MatchResult] { 217 | fatalError() 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /CDN Fetch/Views/AssetCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AssetCell.swift 3 | // CDN Fetch 4 | // 5 | // Created by Charles Kenney on 10/18/17. 6 | // Copyright © 2017 Charles Kenney. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | 13 | class AssetCell: NSTableCellView { 14 | 15 | 16 | var assetName: String? { 17 | didSet { 18 | if let text = assetName { 19 | let ext = AssetType.getExtensionFor(fileName: text) 20 | nameLabel.stringValue = text 21 | fileImage = NSWorkspace.shared.icon(forFileType: ext) 22 | assetType = AssetType.getFileType(forExtension: ext) 23 | } 24 | } 25 | } 26 | 27 | 28 | var assetType: AssetType = .generic { 29 | didSet { 30 | setupFetchMenu() 31 | } 32 | } 33 | 34 | 35 | var fileImage = NSWorkspace.shared.icon(forFileType: "") { 36 | didSet { 37 | setupFileImage() 38 | } 39 | } 40 | 41 | 42 | private var assetUri: String { 43 | let base = "https://cdnjs.cloudflare.com/ajax/libs" 44 | return "\(base)/\(library ?? "")/\(version ?? "")/\(assetName ?? "")" 45 | } 46 | 47 | 48 | var fetchMenu = NSMenu() 49 | 50 | 51 | let nameLabel: NSTextField = { 52 | let label = NSTextField() 53 | label.isBezeled = false 54 | label.isEditable = false 55 | label.isBordered = false 56 | label.font = NSFont(name: "Apple SD Gothic Neo", size: 12) 57 | label.translatesAutoresizingMaskIntoConstraints = false 58 | return label 59 | }() 60 | 61 | 62 | let fileImageView: NSImageView = { 63 | let img = NSImageView() 64 | img.translatesAutoresizingMaskIntoConstraints = false 65 | return img 66 | }() 67 | 68 | 69 | let fetchButton: NSButton = { 70 | let btn = NSButton(image: #imageLiteral(resourceName: "Fetch"), target: nil, action: nil) 71 | btn.translatesAutoresizingMaskIntoConstraints = false 72 | return btn 73 | }() 74 | 75 | 76 | var library: String! 77 | 78 | 79 | var version: String! 80 | 81 | 82 | override func draw(_ dirtyRect: NSRect) { 83 | super.draw(dirtyRect) 84 | setupView() 85 | addViews() 86 | setupFileImageView() 87 | setupFileImage() 88 | setupFetchButton() 89 | setupFetchMenu() 90 | setupNameLabel() 91 | setupPasteboard() 92 | } 93 | 94 | 95 | func setupView() { 96 | self.wantsLayer = false 97 | fetchMenu.delegate = self 98 | } 99 | 100 | 101 | func addViews() { 102 | self.addSubview(fileImageView) 103 | self.addSubview(nameLabel) 104 | self.addSubview(fetchButton) 105 | } 106 | 107 | 108 | func setupFileImageView() { 109 | fileImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true 110 | fileImageView.heightAnchor.constraint(equalToConstant: 30).isActive = true 111 | fileImageView.widthAnchor.constraint(equalToConstant: 30).isActive = true 112 | fileImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true 113 | } 114 | 115 | 116 | func setupFileImage() { 117 | fileImageView.image = fileImage 118 | } 119 | 120 | func setupFetchButton() { 121 | fetchButton.target = self 122 | fetchButton.action = #selector(showMenu(_:)) 123 | fetchButton.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true 124 | fetchButton.heightAnchor.constraint(equalToConstant: 30).isActive = true 125 | fetchButton.widthAnchor.constraint(equalToConstant: 30).isActive = true 126 | fetchButton.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10).isActive = true 127 | } 128 | 129 | func setupFetchMenu() { 130 | fetchMenu = NSMenu() 131 | switch (assetType) { 132 | case .javascript: 133 | // create javascript item 134 | let javascriptItem = NSMenuItem(title: "get " 198 | let pasteboard = NSPasteboard.general 199 | pasteboard.declareTypes([.string], owner: self) 200 | pasteboard.setString(tag, forType: .string) 201 | } 202 | 203 | 204 | @objc func copyUri(_ sender: Any?) { 205 | let pasteboard = NSPasteboard.general 206 | pasteboard.declareTypes([.string], owner: self) 207 | pasteboard.setString(assetUri, forType: .string) 208 | // test (ref for deleting favorites) 209 | if let button = sender as? NSMenuItem { 210 | print(button.tag) 211 | } 212 | } 213 | 214 | 215 | @objc func addToFavorites(_ sender: Any?) { 216 | // get app delegate reference 217 | guard let delegate = NSApplication.shared.delegate as? AppDelegate else { 218 | print("could not get app delegate") 219 | return 220 | } 221 | // get managed object context reference 222 | let context = delegate.persistentContainer.viewContext 223 | // save new favorite entry 224 | let newAsset = NSEntityDescription.insertNewObject(forEntityName: "FavoriteAsset", into: context) as! FavoriteAsset 225 | newAsset.name = assetName ?? "" 226 | newAsset.type = assetType 227 | newAsset.library = library 228 | newAsset.version = version 229 | newAsset.uri = assetUri 230 | delegate.saveAction(nil) 231 | } 232 | 233 | 234 | } 235 | --------------------------------------------------------------------------------