├── .circleci └── config.yml ├── .gitignore ├── CHANGELOG.md ├── Codemine.podspec ├── Codemine.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── Codemine-Mac.xcscheme │ ├── Codemine-tvOS.xcscheme │ ├── Codemine-watchOS.xcscheme │ └── Codemine.xcscheme ├── Codemine ├── Application.swift ├── Extensions │ ├── CGPoint+Utilities.swift │ ├── CGRect+Utilities.swift │ ├── DispatchTime+Utilities.swift │ ├── Extensions+StringInitializable.swift │ ├── Extention+HexInitializable.swift │ ├── NSError+Utilities.swift │ ├── NSURL+Utilities.swift │ ├── String+CaseConverter.swift │ ├── String+EmailValidation.swift │ ├── String+HTML.swift │ ├── String+Range.swift │ ├── UIColor+Hex.swift │ ├── UIImage+Utilities.swift │ ├── UIView+Utilities.swift │ └── URLSession+Codable.swift ├── Operators.swift ├── Supporting Files │ ├── Codemine.h │ └── Info.plist └── Then.swift ├── CodemineTests ├── CodemineTests.swift ├── DispatchTimeTests.swift ├── Extensions │ └── XCTestCase+Utilities.swift ├── Info.plist ├── UIImageTests.swift ├── URLImageAssetSizeTests.swift ├── URLParameterTests.swift ├── add.png └── alert.png ├── LICENSE ├── Package.swift ├── README.md └── Sources ├── Application.swift ├── CGPoint+Utilities.swift ├── CGRect+Utilities.swift ├── GrandCentralDispatch.swift ├── NSError+Utilities.swift ├── NSURL+AssetSize.swift ├── NibInstantiable.swift ├── Operators.swift ├── String+CaseConverter.swift ├── String+EmailValidation.swift ├── String+Range.swift ├── Then.swift ├── UIColor+Hex.swift ├── UIImage+Utilities.swift └── UIView+Utilities.swift /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # iOS CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/ios-migrating-from-1-2/ for more details 4 | # 5 | 6 | ### Codemine config file ### 7 | version: 2 8 | jobs: 9 | build: 10 | 11 | # Specify the Xcode version to use 12 | macos: 13 | xcode: "9.4.1" 14 | 15 | steps: 16 | - checkout 17 | 18 | # Install CocoaPods 19 | # - run: 20 | # name: Install CocoaPods 21 | # command: pod install 22 | 23 | # Build the app and run tests 24 | - run: 25 | name: Build and run tests 26 | command: fastlane scan 27 | environment: 28 | SCAN_DEVICE: iPhone 6 29 | SCAN_SCHEME: Codemine 30 | 31 | # Collect XML test results data to show in the UI, 32 | # and save the same XML files under test-results folder 33 | # in the Artifacts tab 34 | - store_test_results: 35 | path: test_output/report.xml 36 | - store_artifacts: 37 | path: /tmp/test-results 38 | destination: scan-test-results 39 | - store_artifacts: 40 | path: ~/Library/Logs/scan 41 | destination: scan-logs -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | .DS_Store 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata 21 | 22 | ## Other 23 | *.xccheckout 24 | *.moved-aside 25 | *.xcuserstate 26 | *.xcscmblueprint 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | *.ipa 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 63 | 64 | fastlane/report.xml 65 | fastlane/screenshots 66 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.1.0](https://github.com/nodes-ios/Codemine/releases/tag/0.1.0) 2 | Released on 2016-02-19. 3 | 4 | #### Added 5 | - Initial release of Codemine. -------------------------------------------------------------------------------- /Codemine.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint Codemine.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "Codemine" 19 | s.version = "1.1.1" 20 | s.summary = "A gold mine of code, filled with neat utility functions." 21 | 22 | # This description is used to generate tags and improve search results. 23 | # * Think: What does it do? Why did you write it? What is the focus? 24 | # * Try to keep it short, snappy and to the point. 25 | # * Write the description between the DESC delimiters below. 26 | # * Finally, don't worry about the indent, CocoaPods strips it! 27 | s.description = <<-DESC 28 | Codemine is a collection of extensions containing useful functions and syntactic sugar for your Swift project. 29 | DESC 30 | 31 | s.homepage = "https://github.com/nodes-ios/Codemine" 32 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 33 | 34 | 35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 36 | # 37 | # Licensing your code is important. See http://choosealicense.com for more info. 38 | # CocoaPods will detect a license file if there is a named LICENSE* 39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 40 | # 41 | 42 | s.license = "MIT" 43 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 44 | 45 | 46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 47 | # 48 | # Specify the authors of the library, with email addresses. Email addresses 49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 50 | # accepts just a name if you'd rather not provide an email address. 51 | # 52 | # Specify a social_media_url where others can refer to, for example a twitter 53 | # profile URL. 54 | # 55 | 56 | s.author = { "Nodes Agency - iOS" => "ios@nodes.dk" } 57 | s.social_media_url = "http://twitter.com/nodes_ios" 58 | 59 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 60 | # 61 | # If this Pod runs only on iOS or OS X, then specify the platform and 62 | # the deployment target. You can optionally include the target after the platform. 63 | # 64 | 65 | # When using multiple platforms 66 | s.ios.deployment_target = "8.0" 67 | s.osx.deployment_target = "10.10" 68 | s.watchos.deployment_target = "2.0" 69 | s.tvos.deployment_target = "13.0" 70 | 71 | 72 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 73 | # 74 | # Specify the location from where the source should be retrieved. 75 | # Supports git, hg, bzr, svn and HTTP. 76 | # 77 | 78 | s.source = { :git => "https://github.com/nodes-ios/Codemine.git", :tag => s.version.to_s } 79 | 80 | 81 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 82 | # 83 | # CocoaPods is smart about how it includes source code. For source files 84 | # giving a folder will include any swift, h, m, mm, c & cpp files. 85 | # For header files it will include any header in the folder. 86 | # Not including the public_header_files will make all headers public. 87 | # 88 | 89 | s.source_files = "Codemine/**/*.swift" 90 | s.osx.exclude_files = [ 91 | 'Codemine/Extensions/UIColor+Hex.swift', 92 | 'Codemine/Extensions/UIImage+Utilities.swift', 93 | 'Codemine/Extensions/UIView+Utilities.swift', 94 | 'Codemine/Extensions/DispatchTime+Utilities.swift', 95 | 'Codemine/Extensions/String+HTML.swift', 96 | ] 97 | s.watchos.exclude_files = [ 98 | 'Codemine/Extensions/NSURL+Utilities.swift', 99 | 'Codemine/Extensions/UIView+Utilities.swift', 100 | 'Codemine/Extensions/DispatchTime+Utilities.swift', 101 | 'Codemine/Extensions/String+HTML.swift', 102 | ] 103 | s.tvos.exclude_files = [ 104 | 'Codemine/Extensions/DispatchTime+Utilities.swift', 105 | 'Codemine/Extensions/String+HTML.swift', 106 | ] 107 | 108 | # s.public_header_files = "Codemine/Supporting Files/Codemine.h" 109 | 110 | 111 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 112 | # 113 | # A list of resources included with the Pod. These are copied into the 114 | # target bundle with a build phase script. Anything else will be cleaned. 115 | # You can preserve files from being cleaned, please don't preserve 116 | # non-essential files like tests, examples and documentation. 117 | # 118 | 119 | # s.resource = "icon.png" 120 | # s.resources = "Resources/*.png" 121 | 122 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 123 | 124 | 125 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 126 | # 127 | # Link your library with frameworks, or libraries. Libraries do not include 128 | # the lib prefix of their name. 129 | # 130 | 131 | # s.framework = "SomeFramework" 132 | # s.frameworks = "SomeFramework", "AnotherFramework" 133 | 134 | # s.library = "iconv" 135 | # s.libraries = "iconv", "xml2" 136 | 137 | 138 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 139 | # 140 | # If your library depends on compiler flags you can set them in the xcconfig hash 141 | # where they will only apply to your library. If you depend on other Podspecs 142 | # you can include multiple dependencies to ensure it works. 143 | 144 | # s.requires_arc = true 145 | 146 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 147 | # s.dependency "JSONKit", "~> 1.4" 148 | 149 | end 150 | -------------------------------------------------------------------------------- /Codemine.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0132B4CF1C70E616007BC588 /* NSError+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0132B4CE1C70E616007BC588 /* NSError+Utilities.swift */; }; 11 | 01CD402C1D071BAE0044887E /* Codemine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01CD40221D071BAE0044887E /* Codemine.framework */; }; 12 | 01CD40481D071BB50044887E /* Codemine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01CD403E1D071BB50044887E /* Codemine.framework */; }; 13 | 01CD40621D071BCB0044887E /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293490ED1C6CAFD500E8305E /* Application.swift */; }; 14 | 01CD40631D071BCB0044887E /* Then.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293490EF1C6CAFF200E8305E /* Then.swift */; }; 15 | 01CD40651D071BCB0044887E /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CE1C75F32200FB1BBD /* Operators.swift */; }; 16 | 01CD40661D071BCC0044887E /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293490ED1C6CAFD500E8305E /* Application.swift */; }; 17 | 01CD40671D071BCC0044887E /* Then.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293490EF1C6CAFF200E8305E /* Then.swift */; }; 18 | 01CD40691D071BCC0044887E /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CE1C75F32200FB1BBD /* Operators.swift */; }; 19 | 01CD406A1D071BCC0044887E /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293490ED1C6CAFD500E8305E /* Application.swift */; }; 20 | 01CD406B1D071BCC0044887E /* Then.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293490EF1C6CAFF200E8305E /* Then.swift */; }; 21 | 01CD406D1D071BCC0044887E /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CE1C75F32200FB1BBD /* Operators.swift */; }; 22 | 01CD40711D071BDB0044887E /* String+CaseConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272B81C75EC1F00FB1BBD /* String+CaseConverter.swift */; }; 23 | 01CD40721D071BDB0044887E /* String+Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272BA1C75EC2C00FB1BBD /* String+Range.swift */; }; 24 | 01CD40731D071BDB0044887E /* String+EmailValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272BC1C75EC3900FB1BBD /* String+EmailValidation.swift */; }; 25 | 01CD40741D071BDB0044887E /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C21C75EDE300FB1BBD /* CGRect+Utilities.swift */; }; 26 | 01CD40751D071BDB0044887E /* CGPoint+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C41C75EE4F00FB1BBD /* CGPoint+Utilities.swift */; }; 27 | 01CD40761D071BDB0044887E /* NSError+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0132B4CE1C70E616007BC588 /* NSError+Utilities.swift */; }; 28 | 01CD40771D071BDB0044887E /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C01C75ED3900FB1BBD /* UIColor+Hex.swift */; }; 29 | 01CD40791D071BDB0044887E /* UIImage+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CA1C75EEB500FB1BBD /* UIImage+Utilities.swift */; }; 30 | 01CD407B1D071BDC0044887E /* String+CaseConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272B81C75EC1F00FB1BBD /* String+CaseConverter.swift */; }; 31 | 01CD407C1D071BDC0044887E /* String+Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272BA1C75EC2C00FB1BBD /* String+Range.swift */; }; 32 | 01CD407D1D071BDC0044887E /* String+EmailValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272BC1C75EC3900FB1BBD /* String+EmailValidation.swift */; }; 33 | 01CD407E1D071BDC0044887E /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C21C75EDE300FB1BBD /* CGRect+Utilities.swift */; }; 34 | 01CD407F1D071BDC0044887E /* CGPoint+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C41C75EE4F00FB1BBD /* CGPoint+Utilities.swift */; }; 35 | 01CD40801D071BDC0044887E /* NSError+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0132B4CE1C70E616007BC588 /* NSError+Utilities.swift */; }; 36 | 01CD40811D071BDC0044887E /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C01C75ED3900FB1BBD /* UIColor+Hex.swift */; }; 37 | 01CD40821D071BDC0044887E /* NSURL+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C81C75EE9A00FB1BBD /* NSURL+Utilities.swift */; }; 38 | 01CD40831D071BDC0044887E /* UIImage+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CA1C75EEB500FB1BBD /* UIImage+Utilities.swift */; }; 39 | 01CD40841D071BDC0044887E /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CC1C75EECB00FB1BBD /* UIView+Utilities.swift */; }; 40 | 01CD40851D071BDC0044887E /* String+CaseConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272B81C75EC1F00FB1BBD /* String+CaseConverter.swift */; }; 41 | 01CD40861D071BDC0044887E /* String+Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272BA1C75EC2C00FB1BBD /* String+Range.swift */; }; 42 | 01CD40871D071BDC0044887E /* String+EmailValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272BC1C75EC3900FB1BBD /* String+EmailValidation.swift */; }; 43 | 01CD40881D071BDC0044887E /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C21C75EDE300FB1BBD /* CGRect+Utilities.swift */; }; 44 | 01CD40891D071BDC0044887E /* CGPoint+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C41C75EE4F00FB1BBD /* CGPoint+Utilities.swift */; }; 45 | 01CD408A1D071BDC0044887E /* NSError+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0132B4CE1C70E616007BC588 /* NSError+Utilities.swift */; }; 46 | 01CD408F1D071C230044887E /* Codemine.h in Headers */ = {isa = PBXBuildFile; fileRef = 275BCAA21C57D1B500FF3647 /* Codemine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 47 | 01CD40901D071C260044887E /* Codemine.h in Headers */ = {isa = PBXBuildFile; fileRef = 275BCAA21C57D1B500FF3647 /* Codemine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 48 | 01CD40911D071C290044887E /* Codemine.h in Headers */ = {isa = PBXBuildFile; fileRef = 275BCAA21C57D1B500FF3647 /* Codemine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 49 | 275BCAA31C57D1B500FF3647 /* Codemine.h in Headers */ = {isa = PBXBuildFile; fileRef = 275BCAA21C57D1B500FF3647 /* Codemine.h */; settings = {ATTRIBUTES = (Public, ); }; }; 50 | 275BCAAA1C57D1B500FF3647 /* Codemine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 275BCA9F1C57D1B500FF3647 /* Codemine.framework */; }; 51 | 275BCAAF1C57D1B500FF3647 /* CodemineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 275BCAAE1C57D1B500FF3647 /* CodemineTests.swift */; }; 52 | 291272B91C75EC1F00FB1BBD /* String+CaseConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272B81C75EC1F00FB1BBD /* String+CaseConverter.swift */; }; 53 | 291272BB1C75EC2C00FB1BBD /* String+Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272BA1C75EC2C00FB1BBD /* String+Range.swift */; }; 54 | 291272BD1C75EC3900FB1BBD /* String+EmailValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272BC1C75EC3900FB1BBD /* String+EmailValidation.swift */; }; 55 | 291272C11C75ED3900FB1BBD /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C01C75ED3900FB1BBD /* UIColor+Hex.swift */; }; 56 | 291272C31C75EDE300FB1BBD /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C21C75EDE300FB1BBD /* CGRect+Utilities.swift */; }; 57 | 291272C51C75EE4F00FB1BBD /* CGPoint+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C41C75EE4F00FB1BBD /* CGPoint+Utilities.swift */; }; 58 | 291272C91C75EE9A00FB1BBD /* NSURL+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C81C75EE9A00FB1BBD /* NSURL+Utilities.swift */; }; 59 | 291272CB1C75EEB500FB1BBD /* UIImage+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CA1C75EEB500FB1BBD /* UIImage+Utilities.swift */; }; 60 | 291272CD1C75EECB00FB1BBD /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CC1C75EECB00FB1BBD /* UIView+Utilities.swift */; }; 61 | 291272CF1C75F32200FB1BBD /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272CE1C75F32200FB1BBD /* Operators.swift */; }; 62 | 291D23001E0425BF003E1210 /* DispatchTimeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291D22FF1E0425BF003E1210 /* DispatchTimeTests.swift */; }; 63 | 293490EE1C6CAFD500E8305E /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293490ED1C6CAFD500E8305E /* Application.swift */; }; 64 | 293490F01C6CAFF200E8305E /* Then.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293490EF1C6CAFF200E8305E /* Then.swift */; }; 65 | 296831491DD5EC670002FE5A /* DispatchTime+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296831481DD5EC670002FE5A /* DispatchTime+Utilities.swift */; }; 66 | 42DDB213206A61A700A58997 /* Extensions+StringInitializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DDB212206A61A700A58997 /* Extensions+StringInitializable.swift */; }; 67 | 42DDB214206A61A700A58997 /* Extensions+StringInitializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DDB212206A61A700A58997 /* Extensions+StringInitializable.swift */; }; 68 | 42DDB215206A61A700A58997 /* Extensions+StringInitializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DDB212206A61A700A58997 /* Extensions+StringInitializable.swift */; }; 69 | 42DDB216206A61A700A58997 /* Extensions+StringInitializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DDB212206A61A700A58997 /* Extensions+StringInitializable.swift */; }; 70 | 42DDB218206A66A100A58997 /* Extention+HexInitializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DDB217206A66A100A58997 /* Extention+HexInitializable.swift */; }; 71 | 42DDB219206A66A100A58997 /* Extention+HexInitializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DDB217206A66A100A58997 /* Extention+HexInitializable.swift */; }; 72 | 42DDB21A206A66A100A58997 /* Extention+HexInitializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DDB217206A66A100A58997 /* Extention+HexInitializable.swift */; }; 73 | 42DDB21B206A66A100A58997 /* Extention+HexInitializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DDB217206A66A100A58997 /* Extention+HexInitializable.swift */; }; 74 | 42FB12132063D04900F850D1 /* URLSession+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42FB12122063D04900F850D1 /* URLSession+Codable.swift */; }; 75 | 42FB12142063D04900F850D1 /* URLSession+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42FB12122063D04900F850D1 /* URLSession+Codable.swift */; }; 76 | 42FB12152063D04900F850D1 /* URLSession+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42FB12122063D04900F850D1 /* URLSession+Codable.swift */; }; 77 | 42FB12162063D04900F850D1 /* URLSession+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42FB12122063D04900F850D1 /* URLSession+Codable.swift */; }; 78 | 838A0F971F03F57E00469143 /* String+HTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 838A0F961F03F57E00469143 /* String+HTML.swift */; }; 79 | 83A5BEBC1D981F3500C74312 /* UIImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A5BEBB1D981F3500C74312 /* UIImageTests.swift */; }; 80 | 83A5BEBE1D98216000C74312 /* UIImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A5BEBB1D981F3500C74312 /* UIImageTests.swift */; }; 81 | 83A5BEC01D98226800C74312 /* add.png in Resources */ = {isa = PBXBuildFile; fileRef = 83A5BEBF1D98226800C74312 /* add.png */; }; 82 | 83A5BEC11D98226800C74312 /* add.png in Resources */ = {isa = PBXBuildFile; fileRef = 83A5BEBF1D98226800C74312 /* add.png */; }; 83 | 83A5BEC21D98226800C74312 /* add.png in Resources */ = {isa = PBXBuildFile; fileRef = 83A5BEBF1D98226800C74312 /* add.png */; }; 84 | 83A5BEC41D98228300C74312 /* alert.png in Resources */ = {isa = PBXBuildFile; fileRef = 83A5BEC31D98228300C74312 /* alert.png */; }; 85 | 83A5BEC51D98228300C74312 /* alert.png in Resources */ = {isa = PBXBuildFile; fileRef = 83A5BEC31D98228300C74312 /* alert.png */; }; 86 | 83A5BEC61D98228300C74312 /* alert.png in Resources */ = {isa = PBXBuildFile; fileRef = 83A5BEC31D98228300C74312 /* alert.png */; }; 87 | 83A5BEC91D98249500C74312 /* URLImageAssetSizeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A5BEC81D98249500C74312 /* URLImageAssetSizeTests.swift */; }; 88 | 83A5BECA1D98249500C74312 /* URLImageAssetSizeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A5BEC81D98249500C74312 /* URLImageAssetSizeTests.swift */; }; 89 | 83A5BECB1D98249500C74312 /* URLImageAssetSizeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A5BEC81D98249500C74312 /* URLImageAssetSizeTests.swift */; }; 90 | 8C1D2FCE227C79BE00B9C72C /* NSURL+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 291272C81C75EE9A00FB1BBD /* NSURL+Utilities.swift */; }; 91 | 8C9AAA2F1F4ED1F000F9E7C9 /* URLParameterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C9AAA2E1F4ED1F000F9E7C9 /* URLParameterTests.swift */; }; 92 | 9F4A1BBE1F97AF0F00154997 /* XCTestCase+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F4A1BBD1F97AF0F00154997 /* XCTestCase+Utilities.swift */; }; 93 | /* End PBXBuildFile section */ 94 | 95 | /* Begin PBXContainerItemProxy section */ 96 | 01CD402D1D071BAE0044887E /* PBXContainerItemProxy */ = { 97 | isa = PBXContainerItemProxy; 98 | containerPortal = 275BCA961C57D1B400FF3647 /* Project object */; 99 | proxyType = 1; 100 | remoteGlobalIDString = 01CD40211D071BAE0044887E; 101 | remoteInfo = "Codemine-Mac"; 102 | }; 103 | 01CD40491D071BB50044887E /* PBXContainerItemProxy */ = { 104 | isa = PBXContainerItemProxy; 105 | containerPortal = 275BCA961C57D1B400FF3647 /* Project object */; 106 | proxyType = 1; 107 | remoteGlobalIDString = 01CD403D1D071BB50044887E; 108 | remoteInfo = "Codemine-tvOS"; 109 | }; 110 | 275BCAAB1C57D1B500FF3647 /* PBXContainerItemProxy */ = { 111 | isa = PBXContainerItemProxy; 112 | containerPortal = 275BCA961C57D1B400FF3647 /* Project object */; 113 | proxyType = 1; 114 | remoteGlobalIDString = 275BCA9E1C57D1B500FF3647; 115 | remoteInfo = Codemine; 116 | }; 117 | /* End PBXContainerItemProxy section */ 118 | 119 | /* Begin PBXFileReference section */ 120 | 0132B4CE1C70E616007BC588 /* NSError+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSError+Utilities.swift"; sourceTree = ""; }; 121 | 01CD40221D071BAE0044887E /* Codemine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Codemine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 122 | 01CD402B1D071BAE0044887E /* Codemine-MacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Codemine-MacTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 123 | 01CD403E1D071BB50044887E /* Codemine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Codemine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 124 | 01CD40471D071BB50044887E /* Codemine-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Codemine-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 125 | 01CD405A1D071BBD0044887E /* Codemine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Codemine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 126 | 275BCA9F1C57D1B500FF3647 /* Codemine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Codemine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 127 | 275BCAA21C57D1B500FF3647 /* Codemine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Codemine.h; sourceTree = ""; }; 128 | 275BCAA41C57D1B500FF3647 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 129 | 275BCAA91C57D1B500FF3647 /* CodemineTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CodemineTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 130 | 275BCAAE1C57D1B500FF3647 /* CodemineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodemineTests.swift; sourceTree = ""; }; 131 | 275BCAB01C57D1B500FF3647 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 132 | 291272B81C75EC1F00FB1BBD /* String+CaseConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+CaseConverter.swift"; sourceTree = ""; }; 133 | 291272BA1C75EC2C00FB1BBD /* String+Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Range.swift"; sourceTree = ""; }; 134 | 291272BC1C75EC3900FB1BBD /* String+EmailValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+EmailValidation.swift"; sourceTree = ""; }; 135 | 291272C01C75ED3900FB1BBD /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = ""; }; 136 | 291272C21C75EDE300FB1BBD /* CGRect+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGRect+Utilities.swift"; sourceTree = ""; }; 137 | 291272C41C75EE4F00FB1BBD /* CGPoint+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGPoint+Utilities.swift"; sourceTree = ""; }; 138 | 291272C81C75EE9A00FB1BBD /* NSURL+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSURL+Utilities.swift"; sourceTree = ""; }; 139 | 291272CA1C75EEB500FB1BBD /* UIImage+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Utilities.swift"; sourceTree = ""; }; 140 | 291272CC1C75EECB00FB1BBD /* UIView+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Utilities.swift"; sourceTree = ""; }; 141 | 291272CE1C75F32200FB1BBD /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; 142 | 291D22FF1E0425BF003E1210 /* DispatchTimeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchTimeTests.swift; sourceTree = ""; }; 143 | 293490ED1C6CAFD500E8305E /* Application.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; 144 | 293490EF1C6CAFF200E8305E /* Then.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Then.swift; sourceTree = ""; }; 145 | 296831481DD5EC670002FE5A /* DispatchTime+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchTime+Utilities.swift"; sourceTree = ""; }; 146 | 42DDB212206A61A700A58997 /* Extensions+StringInitializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extensions+StringInitializable.swift"; sourceTree = ""; }; 147 | 42DDB217206A66A100A58997 /* Extention+HexInitializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extention+HexInitializable.swift"; sourceTree = ""; }; 148 | 42FB12122063D04900F850D1 /* URLSession+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+Codable.swift"; sourceTree = ""; }; 149 | 838A0F961F03F57E00469143 /* String+HTML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+HTML.swift"; sourceTree = ""; }; 150 | 83A5BEBB1D981F3500C74312 /* UIImageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageTests.swift; sourceTree = ""; }; 151 | 83A5BEBF1D98226800C74312 /* add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = add.png; sourceTree = ""; }; 152 | 83A5BEC31D98228300C74312 /* alert.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = alert.png; sourceTree = ""; }; 153 | 83A5BEC81D98249500C74312 /* URLImageAssetSizeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLImageAssetSizeTests.swift; sourceTree = ""; }; 154 | 8C9AAA2E1F4ED1F000F9E7C9 /* URLParameterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLParameterTests.swift; sourceTree = ""; }; 155 | 9F4A1BBD1F97AF0F00154997 /* XCTestCase+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCTestCase+Utilities.swift"; sourceTree = ""; }; 156 | /* End PBXFileReference section */ 157 | 158 | /* Begin PBXFrameworksBuildPhase section */ 159 | 01CD401E1D071BAE0044887E /* Frameworks */ = { 160 | isa = PBXFrameworksBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | ); 164 | runOnlyForDeploymentPostprocessing = 0; 165 | }; 166 | 01CD40281D071BAE0044887E /* Frameworks */ = { 167 | isa = PBXFrameworksBuildPhase; 168 | buildActionMask = 2147483647; 169 | files = ( 170 | 01CD402C1D071BAE0044887E /* Codemine.framework in Frameworks */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | 01CD403A1D071BB50044887E /* Frameworks */ = { 175 | isa = PBXFrameworksBuildPhase; 176 | buildActionMask = 2147483647; 177 | files = ( 178 | ); 179 | runOnlyForDeploymentPostprocessing = 0; 180 | }; 181 | 01CD40441D071BB50044887E /* Frameworks */ = { 182 | isa = PBXFrameworksBuildPhase; 183 | buildActionMask = 2147483647; 184 | files = ( 185 | 01CD40481D071BB50044887E /* Codemine.framework in Frameworks */, 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | }; 189 | 01CD40561D071BBD0044887E /* Frameworks */ = { 190 | isa = PBXFrameworksBuildPhase; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | 275BCA9B1C57D1B500FF3647 /* Frameworks */ = { 197 | isa = PBXFrameworksBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | }; 203 | 275BCAA61C57D1B500FF3647 /* Frameworks */ = { 204 | isa = PBXFrameworksBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 275BCAAA1C57D1B500FF3647 /* Codemine.framework in Frameworks */, 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXFrameworksBuildPhase section */ 212 | 213 | /* Begin PBXGroup section */ 214 | 275BCA951C57D1B400FF3647 = { 215 | isa = PBXGroup; 216 | children = ( 217 | 275BCAA11C57D1B500FF3647 /* Codemine */, 218 | 275BCAAD1C57D1B500FF3647 /* CodemineTests */, 219 | 275BCAA01C57D1B500FF3647 /* Products */, 220 | ); 221 | sourceTree = ""; 222 | }; 223 | 275BCAA01C57D1B500FF3647 /* Products */ = { 224 | isa = PBXGroup; 225 | children = ( 226 | 275BCA9F1C57D1B500FF3647 /* Codemine.framework */, 227 | 275BCAA91C57D1B500FF3647 /* CodemineTests.xctest */, 228 | 01CD40221D071BAE0044887E /* Codemine.framework */, 229 | 01CD402B1D071BAE0044887E /* Codemine-MacTests.xctest */, 230 | 01CD403E1D071BB50044887E /* Codemine.framework */, 231 | 01CD40471D071BB50044887E /* Codemine-tvOSTests.xctest */, 232 | 01CD405A1D071BBD0044887E /* Codemine.framework */, 233 | ); 234 | name = Products; 235 | sourceTree = ""; 236 | }; 237 | 275BCAA11C57D1B500FF3647 /* Codemine */ = { 238 | isa = PBXGroup; 239 | children = ( 240 | 291272D01C75F37400FB1BBD /* Extensions */, 241 | 293490ED1C6CAFD500E8305E /* Application.swift */, 242 | 293490EF1C6CAFF200E8305E /* Then.swift */, 243 | 291272CE1C75F32200FB1BBD /* Operators.swift */, 244 | 291272D21C75F7CF00FB1BBD /* Supporting Files */, 245 | ); 246 | path = Codemine; 247 | sourceTree = ""; 248 | }; 249 | 275BCAAD1C57D1B500FF3647 /* CodemineTests */ = { 250 | isa = PBXGroup; 251 | children = ( 252 | 9F4A1BBC1F97AEE700154997 /* Extensions */, 253 | 83A5BEC71D98228F00C74312 /* Resources */, 254 | 275BCAB01C57D1B500FF3647 /* Info.plist */, 255 | 275BCAAE1C57D1B500FF3647 /* CodemineTests.swift */, 256 | 83A5BEBB1D981F3500C74312 /* UIImageTests.swift */, 257 | 83A5BEC81D98249500C74312 /* URLImageAssetSizeTests.swift */, 258 | 291D22FF1E0425BF003E1210 /* DispatchTimeTests.swift */, 259 | 8C9AAA2E1F4ED1F000F9E7C9 /* URLParameterTests.swift */, 260 | ); 261 | path = CodemineTests; 262 | sourceTree = ""; 263 | }; 264 | 291272D01C75F37400FB1BBD /* Extensions */ = { 265 | isa = PBXGroup; 266 | children = ( 267 | 291272B81C75EC1F00FB1BBD /* String+CaseConverter.swift */, 268 | 291272BA1C75EC2C00FB1BBD /* String+Range.swift */, 269 | 291272BC1C75EC3900FB1BBD /* String+EmailValidation.swift */, 270 | 291272C21C75EDE300FB1BBD /* CGRect+Utilities.swift */, 271 | 291272C41C75EE4F00FB1BBD /* CGPoint+Utilities.swift */, 272 | 0132B4CE1C70E616007BC588 /* NSError+Utilities.swift */, 273 | 291272C01C75ED3900FB1BBD /* UIColor+Hex.swift */, 274 | 291272C81C75EE9A00FB1BBD /* NSURL+Utilities.swift */, 275 | 291272CA1C75EEB500FB1BBD /* UIImage+Utilities.swift */, 276 | 291272CC1C75EECB00FB1BBD /* UIView+Utilities.swift */, 277 | 296831481DD5EC670002FE5A /* DispatchTime+Utilities.swift */, 278 | 838A0F961F03F57E00469143 /* String+HTML.swift */, 279 | 42FB12122063D04900F850D1 /* URLSession+Codable.swift */, 280 | 42DDB212206A61A700A58997 /* Extensions+StringInitializable.swift */, 281 | 42DDB217206A66A100A58997 /* Extention+HexInitializable.swift */, 282 | ); 283 | path = Extensions; 284 | sourceTree = ""; 285 | }; 286 | 291272D21C75F7CF00FB1BBD /* Supporting Files */ = { 287 | isa = PBXGroup; 288 | children = ( 289 | 275BCAA21C57D1B500FF3647 /* Codemine.h */, 290 | 275BCAA41C57D1B500FF3647 /* Info.plist */, 291 | ); 292 | path = "Supporting Files"; 293 | sourceTree = ""; 294 | }; 295 | 83A5BEC71D98228F00C74312 /* Resources */ = { 296 | isa = PBXGroup; 297 | children = ( 298 | 83A5BEBF1D98226800C74312 /* add.png */, 299 | 83A5BEC31D98228300C74312 /* alert.png */, 300 | ); 301 | name = Resources; 302 | sourceTree = ""; 303 | }; 304 | 9F4A1BBC1F97AEE700154997 /* Extensions */ = { 305 | isa = PBXGroup; 306 | children = ( 307 | 9F4A1BBD1F97AF0F00154997 /* XCTestCase+Utilities.swift */, 308 | ); 309 | path = Extensions; 310 | sourceTree = ""; 311 | }; 312 | /* End PBXGroup section */ 313 | 314 | /* Begin PBXHeadersBuildPhase section */ 315 | 01CD401F1D071BAE0044887E /* Headers */ = { 316 | isa = PBXHeadersBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | 01CD40911D071C290044887E /* Codemine.h in Headers */, 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | 01CD403B1D071BB50044887E /* Headers */ = { 324 | isa = PBXHeadersBuildPhase; 325 | buildActionMask = 2147483647; 326 | files = ( 327 | 01CD40901D071C260044887E /* Codemine.h in Headers */, 328 | ); 329 | runOnlyForDeploymentPostprocessing = 0; 330 | }; 331 | 01CD40571D071BBD0044887E /* Headers */ = { 332 | isa = PBXHeadersBuildPhase; 333 | buildActionMask = 2147483647; 334 | files = ( 335 | 01CD408F1D071C230044887E /* Codemine.h in Headers */, 336 | ); 337 | runOnlyForDeploymentPostprocessing = 0; 338 | }; 339 | 275BCA9C1C57D1B500FF3647 /* Headers */ = { 340 | isa = PBXHeadersBuildPhase; 341 | buildActionMask = 2147483647; 342 | files = ( 343 | 275BCAA31C57D1B500FF3647 /* Codemine.h in Headers */, 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | }; 347 | /* End PBXHeadersBuildPhase section */ 348 | 349 | /* Begin PBXNativeTarget section */ 350 | 01CD40211D071BAE0044887E /* Codemine-Mac */ = { 351 | isa = PBXNativeTarget; 352 | buildConfigurationList = 01CD40371D071BAE0044887E /* Build configuration list for PBXNativeTarget "Codemine-Mac" */; 353 | buildPhases = ( 354 | 01CD401D1D071BAE0044887E /* Sources */, 355 | 01CD401E1D071BAE0044887E /* Frameworks */, 356 | 01CD401F1D071BAE0044887E /* Headers */, 357 | 01CD40201D071BAE0044887E /* Resources */, 358 | ); 359 | buildRules = ( 360 | ); 361 | dependencies = ( 362 | ); 363 | name = "Codemine-Mac"; 364 | productName = "Codemine-Mac"; 365 | productReference = 01CD40221D071BAE0044887E /* Codemine.framework */; 366 | productType = "com.apple.product-type.framework"; 367 | }; 368 | 01CD402A1D071BAE0044887E /* Codemine-MacTests */ = { 369 | isa = PBXNativeTarget; 370 | buildConfigurationList = 01CD40381D071BAE0044887E /* Build configuration list for PBXNativeTarget "Codemine-MacTests" */; 371 | buildPhases = ( 372 | 01CD40271D071BAE0044887E /* Sources */, 373 | 01CD40281D071BAE0044887E /* Frameworks */, 374 | 01CD40291D071BAE0044887E /* Resources */, 375 | ); 376 | buildRules = ( 377 | ); 378 | dependencies = ( 379 | 01CD402E1D071BAE0044887E /* PBXTargetDependency */, 380 | ); 381 | name = "Codemine-MacTests"; 382 | productName = "Codemine-MacTests"; 383 | productReference = 01CD402B1D071BAE0044887E /* Codemine-MacTests.xctest */; 384 | productType = "com.apple.product-type.bundle.unit-test"; 385 | }; 386 | 01CD403D1D071BB50044887E /* Codemine-tvOS */ = { 387 | isa = PBXNativeTarget; 388 | buildConfigurationList = 01CD404F1D071BB50044887E /* Build configuration list for PBXNativeTarget "Codemine-tvOS" */; 389 | buildPhases = ( 390 | 01CD40391D071BB50044887E /* Sources */, 391 | 01CD403A1D071BB50044887E /* Frameworks */, 392 | 01CD403B1D071BB50044887E /* Headers */, 393 | 01CD403C1D071BB50044887E /* Resources */, 394 | ); 395 | buildRules = ( 396 | ); 397 | dependencies = ( 398 | ); 399 | name = "Codemine-tvOS"; 400 | productName = "Codemine-tvOS"; 401 | productReference = 01CD403E1D071BB50044887E /* Codemine.framework */; 402 | productType = "com.apple.product-type.framework"; 403 | }; 404 | 01CD40461D071BB50044887E /* Codemine-tvOSTests */ = { 405 | isa = PBXNativeTarget; 406 | buildConfigurationList = 01CD40521D071BB50044887E /* Build configuration list for PBXNativeTarget "Codemine-tvOSTests" */; 407 | buildPhases = ( 408 | 01CD40431D071BB50044887E /* Sources */, 409 | 01CD40441D071BB50044887E /* Frameworks */, 410 | 01CD40451D071BB50044887E /* Resources */, 411 | ); 412 | buildRules = ( 413 | ); 414 | dependencies = ( 415 | 01CD404A1D071BB50044887E /* PBXTargetDependency */, 416 | ); 417 | name = "Codemine-tvOSTests"; 418 | productName = "Codemine-tvOSTests"; 419 | productReference = 01CD40471D071BB50044887E /* Codemine-tvOSTests.xctest */; 420 | productType = "com.apple.product-type.bundle.unit-test"; 421 | }; 422 | 01CD40591D071BBD0044887E /* Codemine-watchOS */ = { 423 | isa = PBXNativeTarget; 424 | buildConfigurationList = 01CD405F1D071BBD0044887E /* Build configuration list for PBXNativeTarget "Codemine-watchOS" */; 425 | buildPhases = ( 426 | 01CD40551D071BBD0044887E /* Sources */, 427 | 01CD40561D071BBD0044887E /* Frameworks */, 428 | 01CD40571D071BBD0044887E /* Headers */, 429 | 01CD40581D071BBD0044887E /* Resources */, 430 | ); 431 | buildRules = ( 432 | ); 433 | dependencies = ( 434 | ); 435 | name = "Codemine-watchOS"; 436 | productName = "Codemine-watchOS"; 437 | productReference = 01CD405A1D071BBD0044887E /* Codemine.framework */; 438 | productType = "com.apple.product-type.framework"; 439 | }; 440 | 275BCA9E1C57D1B500FF3647 /* Codemine */ = { 441 | isa = PBXNativeTarget; 442 | buildConfigurationList = 275BCAB31C57D1B500FF3647 /* Build configuration list for PBXNativeTarget "Codemine" */; 443 | buildPhases = ( 444 | 275BCA9A1C57D1B500FF3647 /* Sources */, 445 | 275BCA9B1C57D1B500FF3647 /* Frameworks */, 446 | 275BCA9C1C57D1B500FF3647 /* Headers */, 447 | 275BCA9D1C57D1B500FF3647 /* Resources */, 448 | ); 449 | buildRules = ( 450 | ); 451 | dependencies = ( 452 | ); 453 | name = Codemine; 454 | productName = Codemine; 455 | productReference = 275BCA9F1C57D1B500FF3647 /* Codemine.framework */; 456 | productType = "com.apple.product-type.framework"; 457 | }; 458 | 275BCAA81C57D1B500FF3647 /* CodemineTests */ = { 459 | isa = PBXNativeTarget; 460 | buildConfigurationList = 275BCAB61C57D1B500FF3647 /* Build configuration list for PBXNativeTarget "CodemineTests" */; 461 | buildPhases = ( 462 | 275BCAA51C57D1B500FF3647 /* Sources */, 463 | 275BCAA61C57D1B500FF3647 /* Frameworks */, 464 | 275BCAA71C57D1B500FF3647 /* Resources */, 465 | ); 466 | buildRules = ( 467 | ); 468 | dependencies = ( 469 | 275BCAAC1C57D1B500FF3647 /* PBXTargetDependency */, 470 | ); 471 | name = CodemineTests; 472 | productName = CodemineTests; 473 | productReference = 275BCAA91C57D1B500FF3647 /* CodemineTests.xctest */; 474 | productType = "com.apple.product-type.bundle.unit-test"; 475 | }; 476 | /* End PBXNativeTarget section */ 477 | 478 | /* Begin PBXProject section */ 479 | 275BCA961C57D1B400FF3647 /* Project object */ = { 480 | isa = PBXProject; 481 | attributes = { 482 | LastSwiftUpdateCheck = 0730; 483 | LastUpgradeCheck = 1020; 484 | ORGANIZATIONNAME = Nodes; 485 | TargetAttributes = { 486 | 01CD40211D071BAE0044887E = { 487 | CreatedOnToolsVersion = 7.3; 488 | }; 489 | 01CD402A1D071BAE0044887E = { 490 | CreatedOnToolsVersion = 7.3; 491 | }; 492 | 01CD403D1D071BB50044887E = { 493 | CreatedOnToolsVersion = 7.3; 494 | }; 495 | 01CD40461D071BB50044887E = { 496 | CreatedOnToolsVersion = 7.3; 497 | }; 498 | 01CD40591D071BBD0044887E = { 499 | CreatedOnToolsVersion = 7.3; 500 | }; 501 | 275BCA9E1C57D1B500FF3647 = { 502 | CreatedOnToolsVersion = 7.2; 503 | LastSwiftMigration = 1010; 504 | }; 505 | 275BCAA81C57D1B500FF3647 = { 506 | CreatedOnToolsVersion = 7.2; 507 | LastSwiftMigration = 1010; 508 | }; 509 | }; 510 | }; 511 | buildConfigurationList = 275BCA991C57D1B400FF3647 /* Build configuration list for PBXProject "Codemine" */; 512 | compatibilityVersion = "Xcode 3.2"; 513 | developmentRegion = English; 514 | hasScannedForEncodings = 0; 515 | knownRegions = ( 516 | English, 517 | en, 518 | ); 519 | mainGroup = 275BCA951C57D1B400FF3647; 520 | productRefGroup = 275BCAA01C57D1B500FF3647 /* Products */; 521 | projectDirPath = ""; 522 | projectRoot = ""; 523 | targets = ( 524 | 275BCA9E1C57D1B500FF3647 /* Codemine */, 525 | 275BCAA81C57D1B500FF3647 /* CodemineTests */, 526 | 01CD40211D071BAE0044887E /* Codemine-Mac */, 527 | 01CD402A1D071BAE0044887E /* Codemine-MacTests */, 528 | 01CD403D1D071BB50044887E /* Codemine-tvOS */, 529 | 01CD40461D071BB50044887E /* Codemine-tvOSTests */, 530 | 01CD40591D071BBD0044887E /* Codemine-watchOS */, 531 | ); 532 | }; 533 | /* End PBXProject section */ 534 | 535 | /* Begin PBXResourcesBuildPhase section */ 536 | 01CD40201D071BAE0044887E /* Resources */ = { 537 | isa = PBXResourcesBuildPhase; 538 | buildActionMask = 2147483647; 539 | files = ( 540 | ); 541 | runOnlyForDeploymentPostprocessing = 0; 542 | }; 543 | 01CD40291D071BAE0044887E /* Resources */ = { 544 | isa = PBXResourcesBuildPhase; 545 | buildActionMask = 2147483647; 546 | files = ( 547 | 83A5BEC51D98228300C74312 /* alert.png in Resources */, 548 | 83A5BEC11D98226800C74312 /* add.png in Resources */, 549 | ); 550 | runOnlyForDeploymentPostprocessing = 0; 551 | }; 552 | 01CD403C1D071BB50044887E /* Resources */ = { 553 | isa = PBXResourcesBuildPhase; 554 | buildActionMask = 2147483647; 555 | files = ( 556 | ); 557 | runOnlyForDeploymentPostprocessing = 0; 558 | }; 559 | 01CD40451D071BB50044887E /* Resources */ = { 560 | isa = PBXResourcesBuildPhase; 561 | buildActionMask = 2147483647; 562 | files = ( 563 | 83A5BEC61D98228300C74312 /* alert.png in Resources */, 564 | 83A5BEC21D98226800C74312 /* add.png in Resources */, 565 | ); 566 | runOnlyForDeploymentPostprocessing = 0; 567 | }; 568 | 01CD40581D071BBD0044887E /* Resources */ = { 569 | isa = PBXResourcesBuildPhase; 570 | buildActionMask = 2147483647; 571 | files = ( 572 | ); 573 | runOnlyForDeploymentPostprocessing = 0; 574 | }; 575 | 275BCA9D1C57D1B500FF3647 /* Resources */ = { 576 | isa = PBXResourcesBuildPhase; 577 | buildActionMask = 2147483647; 578 | files = ( 579 | ); 580 | runOnlyForDeploymentPostprocessing = 0; 581 | }; 582 | 275BCAA71C57D1B500FF3647 /* Resources */ = { 583 | isa = PBXResourcesBuildPhase; 584 | buildActionMask = 2147483647; 585 | files = ( 586 | 83A5BEC41D98228300C74312 /* alert.png in Resources */, 587 | 83A5BEC01D98226800C74312 /* add.png in Resources */, 588 | ); 589 | runOnlyForDeploymentPostprocessing = 0; 590 | }; 591 | /* End PBXResourcesBuildPhase section */ 592 | 593 | /* Begin PBXSourcesBuildPhase section */ 594 | 01CD401D1D071BAE0044887E /* Sources */ = { 595 | isa = PBXSourcesBuildPhase; 596 | buildActionMask = 2147483647; 597 | files = ( 598 | 01CD40881D071BDC0044887E /* CGRect+Utilities.swift in Sources */, 599 | 42DDB214206A61A700A58997 /* Extensions+StringInitializable.swift in Sources */, 600 | 01CD40891D071BDC0044887E /* CGPoint+Utilities.swift in Sources */, 601 | 01CD40631D071BCB0044887E /* Then.swift in Sources */, 602 | 42DDB219206A66A100A58997 /* Extention+HexInitializable.swift in Sources */, 603 | 01CD40851D071BDC0044887E /* String+CaseConverter.swift in Sources */, 604 | 01CD408A1D071BDC0044887E /* NSError+Utilities.swift in Sources */, 605 | 42FB12142063D04900F850D1 /* URLSession+Codable.swift in Sources */, 606 | 01CD40651D071BCB0044887E /* Operators.swift in Sources */, 607 | 8C1D2FCE227C79BE00B9C72C /* NSURL+Utilities.swift in Sources */, 608 | 01CD40871D071BDC0044887E /* String+EmailValidation.swift in Sources */, 609 | 01CD40621D071BCB0044887E /* Application.swift in Sources */, 610 | 01CD40861D071BDC0044887E /* String+Range.swift in Sources */, 611 | ); 612 | runOnlyForDeploymentPostprocessing = 0; 613 | }; 614 | 01CD40271D071BAE0044887E /* Sources */ = { 615 | isa = PBXSourcesBuildPhase; 616 | buildActionMask = 2147483647; 617 | files = ( 618 | 83A5BECA1D98249500C74312 /* URLImageAssetSizeTests.swift in Sources */, 619 | ); 620 | runOnlyForDeploymentPostprocessing = 0; 621 | }; 622 | 01CD40391D071BB50044887E /* Sources */ = { 623 | isa = PBXSourcesBuildPhase; 624 | buildActionMask = 2147483647; 625 | files = ( 626 | 01CD407E1D071BDC0044887E /* CGRect+Utilities.swift in Sources */, 627 | 01CD407F1D071BDC0044887E /* CGPoint+Utilities.swift in Sources */, 628 | 01CD40831D071BDC0044887E /* UIImage+Utilities.swift in Sources */, 629 | 01CD40821D071BDC0044887E /* NSURL+Utilities.swift in Sources */, 630 | 42DDB21A206A66A100A58997 /* Extention+HexInitializable.swift in Sources */, 631 | 01CD40671D071BCC0044887E /* Then.swift in Sources */, 632 | 01CD407B1D071BDC0044887E /* String+CaseConverter.swift in Sources */, 633 | 01CD40801D071BDC0044887E /* NSError+Utilities.swift in Sources */, 634 | 01CD40841D071BDC0044887E /* UIView+Utilities.swift in Sources */, 635 | 01CD40811D071BDC0044887E /* UIColor+Hex.swift in Sources */, 636 | 01CD40691D071BCC0044887E /* Operators.swift in Sources */, 637 | 01CD407D1D071BDC0044887E /* String+EmailValidation.swift in Sources */, 638 | 01CD40661D071BCC0044887E /* Application.swift in Sources */, 639 | 01CD407C1D071BDC0044887E /* String+Range.swift in Sources */, 640 | 42DDB215206A61A700A58997 /* Extensions+StringInitializable.swift in Sources */, 641 | 42FB12152063D04900F850D1 /* URLSession+Codable.swift in Sources */, 642 | ); 643 | runOnlyForDeploymentPostprocessing = 0; 644 | }; 645 | 01CD40431D071BB50044887E /* Sources */ = { 646 | isa = PBXSourcesBuildPhase; 647 | buildActionMask = 2147483647; 648 | files = ( 649 | 83A5BEBE1D98216000C74312 /* UIImageTests.swift in Sources */, 650 | 83A5BECB1D98249500C74312 /* URLImageAssetSizeTests.swift in Sources */, 651 | ); 652 | runOnlyForDeploymentPostprocessing = 0; 653 | }; 654 | 01CD40551D071BBD0044887E /* Sources */ = { 655 | isa = PBXSourcesBuildPhase; 656 | buildActionMask = 2147483647; 657 | files = ( 658 | 01CD40741D071BDB0044887E /* CGRect+Utilities.swift in Sources */, 659 | 01CD40751D071BDB0044887E /* CGPoint+Utilities.swift in Sources */, 660 | 01CD40791D071BDB0044887E /* UIImage+Utilities.swift in Sources */, 661 | 42FB12162063D04900F850D1 /* URLSession+Codable.swift in Sources */, 662 | 42DDB216206A61A700A58997 /* Extensions+StringInitializable.swift in Sources */, 663 | 01CD406B1D071BCC0044887E /* Then.swift in Sources */, 664 | 42DDB21B206A66A100A58997 /* Extention+HexInitializable.swift in Sources */, 665 | 01CD40711D071BDB0044887E /* String+CaseConverter.swift in Sources */, 666 | 01CD40761D071BDB0044887E /* NSError+Utilities.swift in Sources */, 667 | 01CD40771D071BDB0044887E /* UIColor+Hex.swift in Sources */, 668 | 01CD406D1D071BCC0044887E /* Operators.swift in Sources */, 669 | 01CD40731D071BDB0044887E /* String+EmailValidation.swift in Sources */, 670 | 01CD406A1D071BCC0044887E /* Application.swift in Sources */, 671 | 01CD40721D071BDB0044887E /* String+Range.swift in Sources */, 672 | ); 673 | runOnlyForDeploymentPostprocessing = 0; 674 | }; 675 | 275BCA9A1C57D1B500FF3647 /* Sources */ = { 676 | isa = PBXSourcesBuildPhase; 677 | buildActionMask = 2147483647; 678 | files = ( 679 | 293490EE1C6CAFD500E8305E /* Application.swift in Sources */, 680 | 291272CD1C75EECB00FB1BBD /* UIView+Utilities.swift in Sources */, 681 | 291272C51C75EE4F00FB1BBD /* CGPoint+Utilities.swift in Sources */, 682 | 291272BB1C75EC2C00FB1BBD /* String+Range.swift in Sources */, 683 | 291272C91C75EE9A00FB1BBD /* NSURL+Utilities.swift in Sources */, 684 | 296831491DD5EC670002FE5A /* DispatchTime+Utilities.swift in Sources */, 685 | 42DDB213206A61A700A58997 /* Extensions+StringInitializable.swift in Sources */, 686 | 838A0F971F03F57E00469143 /* String+HTML.swift in Sources */, 687 | 291272C31C75EDE300FB1BBD /* CGRect+Utilities.swift in Sources */, 688 | 291272CB1C75EEB500FB1BBD /* UIImage+Utilities.swift in Sources */, 689 | 291272CF1C75F32200FB1BBD /* Operators.swift in Sources */, 690 | 291272BD1C75EC3900FB1BBD /* String+EmailValidation.swift in Sources */, 691 | 291272B91C75EC1F00FB1BBD /* String+CaseConverter.swift in Sources */, 692 | 293490F01C6CAFF200E8305E /* Then.swift in Sources */, 693 | 0132B4CF1C70E616007BC588 /* NSError+Utilities.swift in Sources */, 694 | 291272C11C75ED3900FB1BBD /* UIColor+Hex.swift in Sources */, 695 | 42DDB218206A66A100A58997 /* Extention+HexInitializable.swift in Sources */, 696 | 42FB12132063D04900F850D1 /* URLSession+Codable.swift in Sources */, 697 | ); 698 | runOnlyForDeploymentPostprocessing = 0; 699 | }; 700 | 275BCAA51C57D1B500FF3647 /* Sources */ = { 701 | isa = PBXSourcesBuildPhase; 702 | buildActionMask = 2147483647; 703 | files = ( 704 | 291D23001E0425BF003E1210 /* DispatchTimeTests.swift in Sources */, 705 | 83A5BEC91D98249500C74312 /* URLImageAssetSizeTests.swift in Sources */, 706 | 9F4A1BBE1F97AF0F00154997 /* XCTestCase+Utilities.swift in Sources */, 707 | 8C9AAA2F1F4ED1F000F9E7C9 /* URLParameterTests.swift in Sources */, 708 | 275BCAAF1C57D1B500FF3647 /* CodemineTests.swift in Sources */, 709 | 83A5BEBC1D981F3500C74312 /* UIImageTests.swift in Sources */, 710 | ); 711 | runOnlyForDeploymentPostprocessing = 0; 712 | }; 713 | /* End PBXSourcesBuildPhase section */ 714 | 715 | /* Begin PBXTargetDependency section */ 716 | 01CD402E1D071BAE0044887E /* PBXTargetDependency */ = { 717 | isa = PBXTargetDependency; 718 | target = 01CD40211D071BAE0044887E /* Codemine-Mac */; 719 | targetProxy = 01CD402D1D071BAE0044887E /* PBXContainerItemProxy */; 720 | }; 721 | 01CD404A1D071BB50044887E /* PBXTargetDependency */ = { 722 | isa = PBXTargetDependency; 723 | target = 01CD403D1D071BB50044887E /* Codemine-tvOS */; 724 | targetProxy = 01CD40491D071BB50044887E /* PBXContainerItemProxy */; 725 | }; 726 | 275BCAAC1C57D1B500FF3647 /* PBXTargetDependency */ = { 727 | isa = PBXTargetDependency; 728 | target = 275BCA9E1C57D1B500FF3647 /* Codemine */; 729 | targetProxy = 275BCAAB1C57D1B500FF3647 /* PBXContainerItemProxy */; 730 | }; 731 | /* End PBXTargetDependency section */ 732 | 733 | /* Begin XCBuildConfiguration section */ 734 | 01CD40331D071BAE0044887E /* Debug */ = { 735 | isa = XCBuildConfiguration; 736 | buildSettings = { 737 | CLANG_ANALYZER_NONNULL = YES; 738 | CODE_SIGN_IDENTITY = "-"; 739 | COMBINE_HIDPI_IMAGES = YES; 740 | DEFINES_MODULE = YES; 741 | DYLIB_COMPATIBILITY_VERSION = 1; 742 | DYLIB_CURRENT_VERSION = 1; 743 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 744 | FRAMEWORK_VERSION = A; 745 | INFOPLIST_FILE = "$(SRCROOT)/Codemine/Supporting Files/Info.plist"; 746 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 747 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 748 | MACOSX_DEPLOYMENT_TARGET = 10.10; 749 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-Mac"; 750 | PRODUCT_NAME = Codemine; 751 | SDKROOT = macosx; 752 | SKIP_INSTALL = YES; 753 | SWIFT_VERSION = 4.2; 754 | }; 755 | name = Debug; 756 | }; 757 | 01CD40341D071BAE0044887E /* Release */ = { 758 | isa = XCBuildConfiguration; 759 | buildSettings = { 760 | CLANG_ANALYZER_NONNULL = YES; 761 | CODE_SIGN_IDENTITY = "-"; 762 | COMBINE_HIDPI_IMAGES = YES; 763 | DEFINES_MODULE = YES; 764 | DYLIB_COMPATIBILITY_VERSION = 1; 765 | DYLIB_CURRENT_VERSION = 1; 766 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 767 | FRAMEWORK_VERSION = A; 768 | INFOPLIST_FILE = "$(SRCROOT)/Codemine/Supporting Files/Info.plist"; 769 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 770 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 771 | MACOSX_DEPLOYMENT_TARGET = 10.10; 772 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-Mac"; 773 | PRODUCT_NAME = Codemine; 774 | SDKROOT = macosx; 775 | SKIP_INSTALL = YES; 776 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 777 | SWIFT_VERSION = 4.2; 778 | }; 779 | name = Release; 780 | }; 781 | 01CD40351D071BAE0044887E /* Debug */ = { 782 | isa = XCBuildConfiguration; 783 | buildSettings = { 784 | CLANG_ANALYZER_NONNULL = YES; 785 | CODE_SIGN_IDENTITY = "-"; 786 | COMBINE_HIDPI_IMAGES = YES; 787 | INFOPLIST_FILE = CodemineTests/Info.plist; 788 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 789 | MACOSX_DEPLOYMENT_TARGET = 10.11; 790 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-MacTests"; 791 | PRODUCT_NAME = "$(TARGET_NAME)"; 792 | SDKROOT = macosx; 793 | SWIFT_VERSION = 4.2; 794 | }; 795 | name = Debug; 796 | }; 797 | 01CD40361D071BAE0044887E /* Release */ = { 798 | isa = XCBuildConfiguration; 799 | buildSettings = { 800 | CLANG_ANALYZER_NONNULL = YES; 801 | CODE_SIGN_IDENTITY = "-"; 802 | COMBINE_HIDPI_IMAGES = YES; 803 | INFOPLIST_FILE = CodemineTests/Info.plist; 804 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 805 | MACOSX_DEPLOYMENT_TARGET = 10.11; 806 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-MacTests"; 807 | PRODUCT_NAME = "$(TARGET_NAME)"; 808 | SDKROOT = macosx; 809 | SWIFT_VERSION = 4.2; 810 | }; 811 | name = Release; 812 | }; 813 | 01CD40501D071BB50044887E /* Debug */ = { 814 | isa = XCBuildConfiguration; 815 | buildSettings = { 816 | CLANG_ANALYZER_NONNULL = YES; 817 | CODE_SIGN_IDENTITY = ""; 818 | DEFINES_MODULE = YES; 819 | DYLIB_COMPATIBILITY_VERSION = 1; 820 | DYLIB_CURRENT_VERSION = 1; 821 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 822 | INFOPLIST_FILE = "$(SRCROOT)/Codemine/Supporting Files/Info.plist"; 823 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 824 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 825 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-tvOS"; 826 | PRODUCT_NAME = Codemine; 827 | SDKROOT = appletvos; 828 | SKIP_INSTALL = YES; 829 | SWIFT_VERSION = 4.2; 830 | TARGETED_DEVICE_FAMILY = 3; 831 | TVOS_DEPLOYMENT_TARGET = 9.0; 832 | }; 833 | name = Debug; 834 | }; 835 | 01CD40511D071BB50044887E /* Release */ = { 836 | isa = XCBuildConfiguration; 837 | buildSettings = { 838 | CLANG_ANALYZER_NONNULL = YES; 839 | CODE_SIGN_IDENTITY = ""; 840 | DEFINES_MODULE = YES; 841 | DYLIB_COMPATIBILITY_VERSION = 1; 842 | DYLIB_CURRENT_VERSION = 1; 843 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 844 | INFOPLIST_FILE = "$(SRCROOT)/Codemine/Supporting Files/Info.plist"; 845 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 846 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 847 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-tvOS"; 848 | PRODUCT_NAME = Codemine; 849 | SDKROOT = appletvos; 850 | SKIP_INSTALL = YES; 851 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 852 | SWIFT_VERSION = 4.2; 853 | TARGETED_DEVICE_FAMILY = 3; 854 | TVOS_DEPLOYMENT_TARGET = 9.0; 855 | }; 856 | name = Release; 857 | }; 858 | 01CD40531D071BB50044887E /* Debug */ = { 859 | isa = XCBuildConfiguration; 860 | buildSettings = { 861 | CLANG_ANALYZER_NONNULL = YES; 862 | INFOPLIST_FILE = CodemineTests/Info.plist; 863 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 864 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-tvOSTests"; 865 | PRODUCT_NAME = "$(TARGET_NAME)"; 866 | SDKROOT = appletvos; 867 | SWIFT_VERSION = 4.2; 868 | TVOS_DEPLOYMENT_TARGET = 9.2; 869 | }; 870 | name = Debug; 871 | }; 872 | 01CD40541D071BB50044887E /* Release */ = { 873 | isa = XCBuildConfiguration; 874 | buildSettings = { 875 | CLANG_ANALYZER_NONNULL = YES; 876 | INFOPLIST_FILE = CodemineTests/Info.plist; 877 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 878 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-tvOSTests"; 879 | PRODUCT_NAME = "$(TARGET_NAME)"; 880 | SDKROOT = appletvos; 881 | SWIFT_VERSION = 4.2; 882 | TVOS_DEPLOYMENT_TARGET = 9.2; 883 | }; 884 | name = Release; 885 | }; 886 | 01CD40601D071BBD0044887E /* Debug */ = { 887 | isa = XCBuildConfiguration; 888 | buildSettings = { 889 | APPLICATION_EXTENSION_API_ONLY = YES; 890 | CLANG_ANALYZER_NONNULL = YES; 891 | CODE_SIGN_IDENTITY = ""; 892 | DEFINES_MODULE = YES; 893 | DYLIB_COMPATIBILITY_VERSION = 1; 894 | DYLIB_CURRENT_VERSION = 1; 895 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 896 | INFOPLIST_FILE = "$(SRCROOT)/Codemine/Supporting Files/Info.plist"; 897 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 898 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 899 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-watchOS"; 900 | PRODUCT_NAME = Codemine; 901 | SDKROOT = watchos; 902 | SKIP_INSTALL = YES; 903 | SWIFT_VERSION = 4.2; 904 | TARGETED_DEVICE_FAMILY = 4; 905 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 906 | }; 907 | name = Debug; 908 | }; 909 | 01CD40611D071BBD0044887E /* Release */ = { 910 | isa = XCBuildConfiguration; 911 | buildSettings = { 912 | APPLICATION_EXTENSION_API_ONLY = YES; 913 | CLANG_ANALYZER_NONNULL = YES; 914 | CODE_SIGN_IDENTITY = ""; 915 | DEFINES_MODULE = YES; 916 | DYLIB_COMPATIBILITY_VERSION = 1; 917 | DYLIB_CURRENT_VERSION = 1; 918 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 919 | INFOPLIST_FILE = "$(SRCROOT)/Codemine/Supporting Files/Info.plist"; 920 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 921 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 922 | PRODUCT_BUNDLE_IDENTIFIER = "com.nodes.Codemine-watchOS"; 923 | PRODUCT_NAME = Codemine; 924 | SDKROOT = watchos; 925 | SKIP_INSTALL = YES; 926 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 927 | SWIFT_VERSION = 4.2; 928 | TARGETED_DEVICE_FAMILY = 4; 929 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 930 | }; 931 | name = Release; 932 | }; 933 | 275BCAB11C57D1B500FF3647 /* Debug */ = { 934 | isa = XCBuildConfiguration; 935 | buildSettings = { 936 | ALWAYS_SEARCH_USER_PATHS = NO; 937 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 938 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 939 | CLANG_CXX_LIBRARY = "libc++"; 940 | CLANG_ENABLE_MODULES = YES; 941 | CLANG_ENABLE_OBJC_ARC = YES; 942 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 943 | CLANG_WARN_BOOL_CONVERSION = YES; 944 | CLANG_WARN_COMMA = YES; 945 | CLANG_WARN_CONSTANT_CONVERSION = YES; 946 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 947 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 948 | CLANG_WARN_EMPTY_BODY = YES; 949 | CLANG_WARN_ENUM_CONVERSION = YES; 950 | CLANG_WARN_INFINITE_RECURSION = YES; 951 | CLANG_WARN_INT_CONVERSION = YES; 952 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 953 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 954 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 955 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 956 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 957 | CLANG_WARN_STRICT_PROTOTYPES = YES; 958 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 959 | CLANG_WARN_UNREACHABLE_CODE = YES; 960 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 961 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 962 | COPY_PHASE_STRIP = NO; 963 | CURRENT_PROJECT_VERSION = 1; 964 | DEBUG_INFORMATION_FORMAT = dwarf; 965 | ENABLE_STRICT_OBJC_MSGSEND = YES; 966 | ENABLE_TESTABILITY = YES; 967 | GCC_C_LANGUAGE_STANDARD = gnu99; 968 | GCC_DYNAMIC_NO_PIC = NO; 969 | GCC_NO_COMMON_BLOCKS = YES; 970 | GCC_OPTIMIZATION_LEVEL = 0; 971 | GCC_PREPROCESSOR_DEFINITIONS = ( 972 | "DEBUG=1", 973 | "$(inherited)", 974 | ); 975 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 976 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 977 | GCC_WARN_UNDECLARED_SELECTOR = YES; 978 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 979 | GCC_WARN_UNUSED_FUNCTION = YES; 980 | GCC_WARN_UNUSED_VARIABLE = YES; 981 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 982 | MACOSX_DEPLOYMENT_TARGET = 10.10; 983 | MTL_ENABLE_DEBUG_INFO = YES; 984 | ONLY_ACTIVE_ARCH = YES; 985 | SDKROOT = iphoneos; 986 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 987 | TARGETED_DEVICE_FAMILY = "1,2"; 988 | VERSIONING_SYSTEM = "apple-generic"; 989 | VERSION_INFO_PREFIX = ""; 990 | }; 991 | name = Debug; 992 | }; 993 | 275BCAB21C57D1B500FF3647 /* Release */ = { 994 | isa = XCBuildConfiguration; 995 | buildSettings = { 996 | ALWAYS_SEARCH_USER_PATHS = NO; 997 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 998 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 999 | CLANG_CXX_LIBRARY = "libc++"; 1000 | CLANG_ENABLE_MODULES = YES; 1001 | CLANG_ENABLE_OBJC_ARC = YES; 1002 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 1003 | CLANG_WARN_BOOL_CONVERSION = YES; 1004 | CLANG_WARN_COMMA = YES; 1005 | CLANG_WARN_CONSTANT_CONVERSION = YES; 1006 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 1007 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 1008 | CLANG_WARN_EMPTY_BODY = YES; 1009 | CLANG_WARN_ENUM_CONVERSION = YES; 1010 | CLANG_WARN_INFINITE_RECURSION = YES; 1011 | CLANG_WARN_INT_CONVERSION = YES; 1012 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 1013 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 1014 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 1015 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 1016 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 1017 | CLANG_WARN_STRICT_PROTOTYPES = YES; 1018 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 1019 | CLANG_WARN_UNREACHABLE_CODE = YES; 1020 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 1021 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 1022 | COPY_PHASE_STRIP = NO; 1023 | CURRENT_PROJECT_VERSION = 1; 1024 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 1025 | ENABLE_NS_ASSERTIONS = NO; 1026 | ENABLE_STRICT_OBJC_MSGSEND = YES; 1027 | GCC_C_LANGUAGE_STANDARD = gnu99; 1028 | GCC_NO_COMMON_BLOCKS = YES; 1029 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 1030 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 1031 | GCC_WARN_UNDECLARED_SELECTOR = YES; 1032 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 1033 | GCC_WARN_UNUSED_FUNCTION = YES; 1034 | GCC_WARN_UNUSED_VARIABLE = YES; 1035 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 1036 | MACOSX_DEPLOYMENT_TARGET = 10.10; 1037 | MTL_ENABLE_DEBUG_INFO = NO; 1038 | SDKROOT = iphoneos; 1039 | SWIFT_COMPILATION_MODE = wholemodule; 1040 | TARGETED_DEVICE_FAMILY = "1,2"; 1041 | VALIDATE_PRODUCT = YES; 1042 | VERSIONING_SYSTEM = "apple-generic"; 1043 | VERSION_INFO_PREFIX = ""; 1044 | }; 1045 | name = Release; 1046 | }; 1047 | 275BCAB41C57D1B500FF3647 /* Debug */ = { 1048 | isa = XCBuildConfiguration; 1049 | buildSettings = { 1050 | APPLICATION_EXTENSION_API_ONLY = YES; 1051 | CLANG_ENABLE_MODULES = YES; 1052 | CODE_SIGN_IDENTITY = ""; 1053 | DEFINES_MODULE = YES; 1054 | DYLIB_COMPATIBILITY_VERSION = 1; 1055 | DYLIB_CURRENT_VERSION = 1; 1056 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1057 | INFOPLIST_FILE = "Codemine/Supporting Files/Info.plist"; 1058 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1059 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1060 | PRODUCT_BUNDLE_IDENTIFIER = com.nodes.Codemine; 1061 | PRODUCT_NAME = "$(TARGET_NAME)"; 1062 | SKIP_INSTALL = YES; 1063 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 1064 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 1065 | SWIFT_VERSION = 4.2; 1066 | }; 1067 | name = Debug; 1068 | }; 1069 | 275BCAB51C57D1B500FF3647 /* Release */ = { 1070 | isa = XCBuildConfiguration; 1071 | buildSettings = { 1072 | APPLICATION_EXTENSION_API_ONLY = YES; 1073 | CLANG_ENABLE_MODULES = YES; 1074 | CODE_SIGN_IDENTITY = ""; 1075 | DEFINES_MODULE = YES; 1076 | DYLIB_COMPATIBILITY_VERSION = 1; 1077 | DYLIB_CURRENT_VERSION = 1; 1078 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1079 | INFOPLIST_FILE = "Codemine/Supporting Files/Info.plist"; 1080 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1081 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1082 | PRODUCT_BUNDLE_IDENTIFIER = com.nodes.Codemine; 1083 | PRODUCT_NAME = "$(TARGET_NAME)"; 1084 | SKIP_INSTALL = YES; 1085 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1086 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 1087 | SWIFT_VERSION = 4.2; 1088 | }; 1089 | name = Release; 1090 | }; 1091 | 275BCAB71C57D1B500FF3647 /* Debug */ = { 1092 | isa = XCBuildConfiguration; 1093 | buildSettings = { 1094 | INFOPLIST_FILE = CodemineTests/Info.plist; 1095 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1096 | PRODUCT_BUNDLE_IDENTIFIER = com.nodes.CodemineTests; 1097 | PRODUCT_NAME = "$(TARGET_NAME)"; 1098 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 1099 | SWIFT_VERSION = 4.2; 1100 | }; 1101 | name = Debug; 1102 | }; 1103 | 275BCAB81C57D1B500FF3647 /* Release */ = { 1104 | isa = XCBuildConfiguration; 1105 | buildSettings = { 1106 | INFOPLIST_FILE = CodemineTests/Info.plist; 1107 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1108 | PRODUCT_BUNDLE_IDENTIFIER = com.nodes.CodemineTests; 1109 | PRODUCT_NAME = "$(TARGET_NAME)"; 1110 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1111 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 1112 | SWIFT_VERSION = 4.2; 1113 | }; 1114 | name = Release; 1115 | }; 1116 | /* End XCBuildConfiguration section */ 1117 | 1118 | /* Begin XCConfigurationList section */ 1119 | 01CD40371D071BAE0044887E /* Build configuration list for PBXNativeTarget "Codemine-Mac" */ = { 1120 | isa = XCConfigurationList; 1121 | buildConfigurations = ( 1122 | 01CD40331D071BAE0044887E /* Debug */, 1123 | 01CD40341D071BAE0044887E /* Release */, 1124 | ); 1125 | defaultConfigurationIsVisible = 0; 1126 | defaultConfigurationName = Release; 1127 | }; 1128 | 01CD40381D071BAE0044887E /* Build configuration list for PBXNativeTarget "Codemine-MacTests" */ = { 1129 | isa = XCConfigurationList; 1130 | buildConfigurations = ( 1131 | 01CD40351D071BAE0044887E /* Debug */, 1132 | 01CD40361D071BAE0044887E /* Release */, 1133 | ); 1134 | defaultConfigurationIsVisible = 0; 1135 | defaultConfigurationName = Release; 1136 | }; 1137 | 01CD404F1D071BB50044887E /* Build configuration list for PBXNativeTarget "Codemine-tvOS" */ = { 1138 | isa = XCConfigurationList; 1139 | buildConfigurations = ( 1140 | 01CD40501D071BB50044887E /* Debug */, 1141 | 01CD40511D071BB50044887E /* Release */, 1142 | ); 1143 | defaultConfigurationIsVisible = 0; 1144 | defaultConfigurationName = Release; 1145 | }; 1146 | 01CD40521D071BB50044887E /* Build configuration list for PBXNativeTarget "Codemine-tvOSTests" */ = { 1147 | isa = XCConfigurationList; 1148 | buildConfigurations = ( 1149 | 01CD40531D071BB50044887E /* Debug */, 1150 | 01CD40541D071BB50044887E /* Release */, 1151 | ); 1152 | defaultConfigurationIsVisible = 0; 1153 | defaultConfigurationName = Release; 1154 | }; 1155 | 01CD405F1D071BBD0044887E /* Build configuration list for PBXNativeTarget "Codemine-watchOS" */ = { 1156 | isa = XCConfigurationList; 1157 | buildConfigurations = ( 1158 | 01CD40601D071BBD0044887E /* Debug */, 1159 | 01CD40611D071BBD0044887E /* Release */, 1160 | ); 1161 | defaultConfigurationIsVisible = 0; 1162 | defaultConfigurationName = Release; 1163 | }; 1164 | 275BCA991C57D1B400FF3647 /* Build configuration list for PBXProject "Codemine" */ = { 1165 | isa = XCConfigurationList; 1166 | buildConfigurations = ( 1167 | 275BCAB11C57D1B500FF3647 /* Debug */, 1168 | 275BCAB21C57D1B500FF3647 /* Release */, 1169 | ); 1170 | defaultConfigurationIsVisible = 0; 1171 | defaultConfigurationName = Release; 1172 | }; 1173 | 275BCAB31C57D1B500FF3647 /* Build configuration list for PBXNativeTarget "Codemine" */ = { 1174 | isa = XCConfigurationList; 1175 | buildConfigurations = ( 1176 | 275BCAB41C57D1B500FF3647 /* Debug */, 1177 | 275BCAB51C57D1B500FF3647 /* Release */, 1178 | ); 1179 | defaultConfigurationIsVisible = 0; 1180 | defaultConfigurationName = Release; 1181 | }; 1182 | 275BCAB61C57D1B500FF3647 /* Build configuration list for PBXNativeTarget "CodemineTests" */ = { 1183 | isa = XCConfigurationList; 1184 | buildConfigurations = ( 1185 | 275BCAB71C57D1B500FF3647 /* Debug */, 1186 | 275BCAB81C57D1B500FF3647 /* Release */, 1187 | ); 1188 | defaultConfigurationIsVisible = 0; 1189 | defaultConfigurationName = Release; 1190 | }; 1191 | /* End XCConfigurationList section */ 1192 | }; 1193 | rootObject = 275BCA961C57D1B400FF3647 /* Project object */; 1194 | } 1195 | -------------------------------------------------------------------------------- /Codemine.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Codemine.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Codemine.xcodeproj/xcshareddata/xcschemes/Codemine-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Codemine.xcodeproj/xcshareddata/xcschemes/Codemine-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Codemine.xcodeproj/xcshareddata/xcschemes/Codemine-watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Codemine.xcodeproj/xcshareddata/xcschemes/Codemine.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Codemine/Application.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Hyper Interaktiv AS 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining 4 | // a copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to 8 | // permit persons to whom the Software is furnished to do so, subject to 9 | // the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be 12 | // included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | import Foundation 23 | 24 | public struct Application { 25 | 26 | fileprivate static func getString(_ key: String) -> String { 27 | guard let infoDictionary = Bundle.main.infoDictionary, 28 | let value = infoDictionary[key] as? String 29 | else { return "" } 30 | 31 | return value 32 | } 33 | 34 | public static var name: String = { 35 | return Application.getString("CFBundleDisplayName") 36 | }() 37 | 38 | public static var version: String = { 39 | return Application.getString("CFBundleShortVersionString") 40 | }() 41 | 42 | public static var build: String = { 43 | return Application.getString("CFBundleVersion") 44 | }() 45 | 46 | public static var executable: String = { 47 | return Application.getString("CFBundleExecutable") 48 | }() 49 | 50 | public static var bundle: String = { 51 | return Application.getString("CFBundleIdentifier") 52 | }() 53 | 54 | public static var schemes: [String] = { 55 | guard let infoDictionary = Bundle.main.infoDictionary, 56 | let urlTypes = infoDictionary["CFBundleURLTypes"] as? [AnyObject], 57 | let urlType = urlTypes.first as? [String : AnyObject], 58 | let urlSchemes = urlType["CFBundleURLSchemes"] as? [String] 59 | else { return [] } 60 | 61 | return urlSchemes 62 | }() 63 | 64 | public static var mainScheme: String? = { 65 | return schemes.first 66 | }() 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Codemine/Extensions/CGPoint+Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPoint+Utilities.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreGraphics 11 | 12 | public extension CGPoint { 13 | /** 14 | Check if a `CGPoint` is close to another `CGPoint`. 15 | There is a tolerance that defines the range that is tolerated to call it close to another `CGPoint`. 16 | If the actual point is close to the `point` from the parameter it will return true. 17 | 18 | - Parameters: 19 | - point: The `CGPoint` that will be checked if it is close to the actual `CGPoint`. 20 | - tolerance: Defines what range is tolerated to be close to the other `point`. 21 | 22 | - Returns: `Boolean` - if close to return true, else false. 23 | */ 24 | func isCloseTo(_ point: CGPoint, tolerance: CGFloat) -> Bool { 25 | let xIsClose = self.x <= point.x + tolerance && self.x >= point.x - tolerance 26 | let yIsClose = self.y <= point.y + tolerance && self.y >= point.y - tolerance 27 | return xIsClose && yIsClose 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /Codemine/Extensions/CGRect+Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGRect+Utilities.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreGraphics 11 | 12 | public extension CGRect { 13 | /// Getter & Setter for a `CGRect`'s `origin.y` 14 | var y: CGFloat { 15 | set { 16 | self = CGRect(origin: CGPoint(x: origin.x, y: newValue), size: size) 17 | } 18 | get { 19 | return self.origin.y 20 | } 21 | } 22 | 23 | /// Getter & Setter for a `CGRect`s `origin.x` 24 | var x: CGFloat { 25 | set { 26 | self = CGRect(origin: CGPoint(x: newValue, y: origin.y), size: size) 27 | } 28 | get { 29 | return self.origin.x 30 | } 31 | } 32 | 33 | /** 34 | Reverses the width and height of a 'CGRect' 35 | 36 | - returns: a new CGRect with the width and height reversed to those of the current one 37 | */ 38 | var reversingSize: CGRect { 39 | return CGRect(origin: origin, size: CGSize(width: height, height: width)) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Codemine/Extensions/DispatchTime+Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DispatchTime+Utilities.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 11/11/2016. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // Credits for this go to Russ Bishop http://www.russbishop.net/quick-easy-dispatchtime 12 | 13 | extension DispatchTime: ExpressibleByIntegerLiteral { 14 | public init(integerLiteral value: Int) { 15 | self = DispatchTime.now() + .seconds(value) 16 | } 17 | } 18 | 19 | extension DispatchTime: ExpressibleByFloatLiteral { 20 | public init(floatLiteral value: Double) { 21 | self = DispatchTime.now() + .milliseconds(Int(value * 1000)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Codemine/Extensions/Extensions+StringInitializable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // Serializable 4 | // 5 | // Created by Chris Combs on 16/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: - Protocols - 12 | // MARK: String Initializable 13 | 14 | public protocol StringInitializable { 15 | static func fromString(_ string: String) -> T? 16 | func stringRepresentation() -> String 17 | } 18 | 19 | extension URL: StringInitializable { 20 | public static func fromString(_ string: String) -> T? { 21 | return self.init(string: string) as? T 22 | } 23 | 24 | public func stringRepresentation() -> String { 25 | return self.absoluteString 26 | } 27 | } 28 | 29 | extension Date: StringInitializable { 30 | static fileprivate let internalDateFormatter = DateFormatter() 31 | static fileprivate let allowedDateFormats = ["yyyy-MM-dd'T'HH:mm:ssZZZZZ", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd"] 32 | static public var customDateFormats: [String] = [] 33 | 34 | public static func fromString(_ string: String) -> T? { 35 | for format in allowedDateFormats + customDateFormats { 36 | internalDateFormatter.dateFormat = format 37 | if let date = internalDateFormatter.date(from: string) as? T { 38 | return date 39 | } 40 | } 41 | 42 | return nil 43 | } 44 | 45 | public func stringRepresentation() -> String { 46 | Date.internalDateFormatter.dateFormat = Date.allowedDateFormats.first 47 | return Date.internalDateFormatter.string(from: self) 48 | } 49 | } 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Codemine/Extensions/Extention+HexInitializable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extention+HexInitializable.swift 3 | // Codemine 4 | // 5 | // Created by Andrei Hogea on 27/03/2018. 6 | // Copyright © 2018 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: Hex Initializable 12 | #if os(OSX) 13 | import Cocoa 14 | typealias Color = NSColor 15 | #else 16 | import UIKit 17 | typealias Color = UIColor 18 | #endif 19 | 20 | public protocol HexInitializable { 21 | static func fromHexString(_ hexString: String) -> T? 22 | } 23 | 24 | extension Color: HexInitializable { 25 | 26 | public static func fromHexString(_ hexString: String) -> T? { 27 | let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) 28 | var int = UInt32() 29 | let a, r, g, b: UInt32 30 | 31 | guard Scanner(string: hex).scanHexInt32(&int) else { 32 | return nil 33 | } 34 | 35 | switch hex.count { 36 | // RGB (12-bit) 37 | case 3: 38 | (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) 39 | // RRGGBB (24-bit) 40 | case 6: 41 | (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) 42 | // ARGB (32-bit) 43 | case 8: 44 | (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) 45 | default: 46 | return nil 47 | } 48 | 49 | return self.init(red: CGFloat(r) / 255, 50 | green: CGFloat(g) / 255, 51 | blue: CGFloat(b) / 255, 52 | alpha: CGFloat(a) / 255) as? T 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Codemine/Extensions/NSError+Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Errors.swift 3 | // Codemine 4 | // 5 | // Created by Dominik Hádl on 14/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public extension NSError { 13 | /** 14 | Convenience initializer for an NSError 15 | 16 | - parameter domain: The error domain—this can be one of the predefined NSError domains, or an arbitrary string describing a custom domain. domain must not be nil. 17 | - parameter code: The error code for the error. 18 | - parameter description: The description of the error. Corresponds to the `NSLocalizedDescriptionKey` in the 'userInfo' dictionary 19 | 20 | - returns: An NSError object initialized for domain with the specified error code and the description. 21 | */ 22 | convenience init(domain: String, code: Int, description: String) { 23 | self.init(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey : description]) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Codemine/Extensions/NSURL+Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSURL+Utilities.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreGraphics 11 | #if os(iOS) || os(tvOS) 12 | import UIKit 13 | #else 14 | import AppKit 15 | #endif 16 | 17 | public extension URL { 18 | /** 19 | Mode for image urls. 20 | It defines in which mode an image will be provided. 21 | 22 | - Resize: Resize image mode. The image can be streched or compressed. 23 | - Crop: Cropped image mode. It will crop into an image so only a part of the image will be provided. 24 | If no value is explicitly set, the default behavior is to center the image. 25 | - Fit: Resizes the image to fit within the width and height boundaries without cropping or distorting the image. 26 | The resulting image is assured to match one of the constraining dimensions, 27 | while the other dimension is altered to maintain the same aspect ratio of the input image. 28 | - Standard: Default/normal image mode. No changes to the ratio. 29 | */ 30 | enum ImageUrlMode : String { 31 | case resize = "resize" 32 | case crop = "crop" 33 | case fit = "fit" 34 | case `default` = "default" 35 | } 36 | 37 | /** 38 | Adds height, width and mode paramters to an url. To be used when fetching an image from a CDN, for example. 39 | Choose the `size` and the `mode` for the image url to define how an image will be provided from the backend. 40 | 41 | - parameters: 42 | - size: Set `size` as `CGSize` to define the size of the image that will be provided. 43 | - mode: Select a mode from predefined `ImageUrlMode` to set up a mode and define how an image will be provided. 44 | - heightParameterName: the name of the height paramter. Default is 'h' 45 | - widthParameterName: the name of the width paramter. Default is 'h' 46 | - returns: `URL` as a `NSURL`. 47 | */ 48 | func appendingAssetSize(_ size: CGSize, mode: ImageUrlMode = .default, heightParameterName : String = "h", widthParameterName : String = "w") -> URL? { 49 | guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: false) else { return nil } 50 | 51 | #if os(iOS) || os(tvOS) 52 | let screenScale = UIScreen.main.scale 53 | #else 54 | let screenScale = NSScreen.main?.backingScaleFactor ?? 1.0 55 | #endif 56 | 57 | var queryItems:[URLQueryItem] = urlComponents.queryItems ?? [] 58 | queryItems.append(URLQueryItem(name: widthParameterName, value: "\(Int(size.width * screenScale ))")) 59 | queryItems.append(URLQueryItem(name: heightParameterName, value: "\(Int(size.height * screenScale ))")) 60 | if mode != .default { 61 | queryItems.append(URLQueryItem(name: "mode", value: mode.rawValue)) 62 | } 63 | urlComponents.queryItems = queryItems 64 | return urlComponents.url 65 | } 66 | 67 | /** 68 | Finds the first value for a URL parameter in a `URL` 69 | - parameters: 70 | - name: the URL parameter to look for 71 | - returns: the first value found for `name` or nil if no value was found 72 | */ 73 | func value(forParameter name: String) -> String? { 74 | guard let urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: true), 75 | let queryItems = urlComponents.queryItems else { 76 | return nil 77 | } 78 | let items = queryItems.filter({ $0.name == name }) 79 | return items.first?.value 80 | } 81 | 82 | /** 83 | Appends queryParameters to a `URL` 84 | - parameters: 85 | - queryParameters: a `String` : `String` dictionary containing the queryParameters to append 86 | - returns: a new `URL` instance with the appended queryParameters or nil if the appending failed 87 | */ 88 | func append(queryParameters: [String: String]) -> URL? { 89 | guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: true) else { 90 | return nil 91 | } 92 | 93 | let urlQueryItems = queryParameters.map{ 94 | return URLQueryItem(name: $0, value: $1) 95 | } 96 | urlComponents.queryItems = urlQueryItems 97 | return urlComponents.url 98 | } 99 | 100 | /// Changes a value for a queryParameter in a given URL 101 | /// 102 | /// - Parameters: 103 | /// - url: The `URL` that you want to change a queryParemeter in 104 | /// - withName: The `String` representation of the name of the queryParameter you want to change the value of 105 | /// - toValue: The `String` representation of the new value for the queryParameter 106 | /// - Returns: A new `URL` instance with a changed queryParameter value, for the first param that matches the input, or nil if the change failed 107 | func changeQueryParamValue(withName param: String, to newValue: String) -> URL? { 108 | 109 | if self.value(forParameter: param) != nil { 110 | if 111 | var component = URLComponents(url: self, resolvingAgainstBaseURL: false), 112 | var queryItems = component.queryItems, 113 | let index = queryItems.firstIndex(where: {$0.name == param}) 114 | { 115 | queryItems[index].value = newValue 116 | component.queryItems = queryItems 117 | 118 | return component.url 119 | } 120 | } 121 | return nil 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /Codemine/Extensions/String+CaseConverter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+CaseConverter.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public extension String { 13 | /** 14 | Returns a snake_case String based on the current camelCase string. For example, userId will be transformed into user_id 15 | 16 | - returns: the snake_case String 17 | */ 18 | func camelCaseToUnderscore() -> String { 19 | var returnString = self 20 | 21 | let characterArray = Array(returnString).map { (character) -> String in 22 | let inputCharacterString = String(character) 23 | let lowerCaseCharacterString = String(character).lowercased() 24 | 25 | if inputCharacterString != lowerCaseCharacterString { 26 | return "_" + lowerCaseCharacterString 27 | } 28 | 29 | return inputCharacterString 30 | } 31 | 32 | returnString = characterArray.reduce("") { 33 | return $0 + $1 34 | } 35 | 36 | return returnString 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Codemine/Extensions/String+EmailValidation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+EmailValidation.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public extension String { 13 | 14 | /** 15 | Checks if the current string is a valid email address. 16 | 17 | - returns: true is the current string is a valid email address, false otherwise 18 | */ 19 | var isValidEmailAddress: Bool { 20 | let emailRegex = "\\A[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\z" 21 | let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegex) 22 | return emailTest.evaluate(with: self) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Codemine/Extensions/String+HTML.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+HTML.swift 3 | // Codemine 4 | // 5 | // Created by Chris on 28/06/2017. 6 | // Copyright © 2017 Nodes. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public func stringFromHtml(string: String) -> NSAttributedString? { 12 | do { 13 | let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true) 14 | if let d = data { 15 | let str = try NSAttributedString(data: d, 16 | options: [ 17 | NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html, 18 | NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue], 19 | documentAttributes: nil) 20 | return str 21 | } 22 | } catch { 23 | print(error) 24 | } 25 | return nil 26 | } 27 | 28 | extension UILabel { 29 | public convenience init(htmlString: String) { 30 | self.init() 31 | numberOfLines = 0 32 | lineBreakMode = .byWordWrapping 33 | attributedText = htmlString.attributedHTMLString 34 | } 35 | } 36 | 37 | extension String { 38 | public var attributedHTMLString: NSAttributedString? { 39 | return stringFromHtml(string: self) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Codemine/Extensions/String+Range.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Range.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | public extension String { 13 | /** 14 | Checks if a range appears in a String. 15 | 16 | - parameter range: the range that is checked 17 | 18 | - returns: true if the string contains that range, false otherwise 19 | */ 20 | private func contains(_ range: Range) -> Bool { 21 | if range.lowerBound < self.startIndex || range.upperBound > self.endIndex { 22 | return false 23 | } 24 | 25 | return true 26 | } 27 | 28 | enum RangeSearchType: Int { 29 | case leftToRight 30 | case rightToLeft 31 | case broadest 32 | case narrowest 33 | } 34 | 35 | /** 36 | Returns the range between two substrings, including the 2 substrings. 37 | 38 | - parameter string: first substring 39 | - parameter toString: second substring 40 | - parameter searchType: direction of search 41 | - parameter inRange: the range of the string in which the search is performed. If nil, it will be done in the whole string. 42 | 43 | - returns: the range between the start of the first substring and the end of the last substring 44 | */ 45 | func range(from fromString: String, toString: String, searchType: RangeSearchType = .leftToRight, inRange: Range? = nil) -> Range? { 46 | let range = inRange ?? Range(uncheckedBounds: (lower: self.startIndex, upper: self.endIndex)) 47 | if !contains(range) { return nil } 48 | 49 | guard let firstRange = self.range(of: fromString, options: NSString.CompareOptions(rawValue: 0), range: range, locale: nil) else { return nil } 50 | guard let secondRange = self.range(of: toString, options: NSString.CompareOptions(rawValue: 0), range: range, locale: nil) else { return nil } 51 | 52 | switch searchType { 53 | case .leftToRight: 54 | return firstRange.lowerBound..> 16) / 255.0, 24 | green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0, 25 | blue: CGFloat(rgb & 0x0000FF) / 255.0, 26 | alpha: CGFloat(1.0) 27 | ) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Codemine/Extensions/UIImage+Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Utilities.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public extension UIImage { 13 | /** 14 | Create an `UIImage` with specified background color, size and corner radius. 15 | 16 | Parameter `color` is used for the background color, 17 | parameter `size` to set the size of the the holder rectangle, 18 | parameter `cornerRadius` for setting up the rounded corners. 19 | 20 | - Parameters: 21 | - color: The background color. 22 | - size: The size of the image. 23 | - cornerRadius: The corner radius. 24 | 25 | - Returns: A 'UIImage' with the specified color, size and corner radius. 26 | */ 27 | 28 | convenience init(color: UIColor, size: CGSize, cornerRadius: CGFloat) { 29 | self.init() 30 | 31 | /// The base rectangle of the image. 32 | let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) 33 | UIGraphicsBeginImageContext(rect.size) 34 | 35 | /// The graphics context of the image. 36 | let context = UIGraphicsGetCurrentContext() 37 | context?.setFillColor(color.cgColor) 38 | context?.fill(rect) 39 | 40 | /// Image that will be retured. 41 | var image = UIGraphicsGetImageFromCurrentImageContext() 42 | UIGraphicsEndImageContext() 43 | 44 | UIGraphicsBeginImageContext(size) 45 | 46 | UIBezierPath(roundedRect: rect, cornerRadius:cornerRadius).addClip() 47 | image?.draw(in: rect) 48 | 49 | image = UIGraphicsGetImageFromCurrentImageContext() 50 | UIGraphicsEndImageContext() 51 | 52 | } 53 | 54 | 55 | /** 56 | Embed an icon/image on top of a background image. 57 | 58 | `image` will be the background and `icon` is the image that will be on top of `image`. 59 | The `UIImage` that is set with the parameter `icon` will be centered on `image`. 60 | 61 | - Parameters: 62 | - icon: The embedded image that will be on top. 63 | - image: The background image. 64 | - Returns: The combined image as `UIImage`. 65 | */ 66 | class func embed(icon: UIImage, inImage image: UIImage ) -> UIImage? { 67 | let newSize = CGSize(width: image.size.width, height: image.size.height) 68 | UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0) 69 | 70 | image.draw(in: CGRect(x: 0,y: 0,width: newSize.width,height: newSize.height)) 71 | 72 | // Center icon 73 | icon.draw(in: CGRect(x: image.size.width/2 - icon.size.width/2, y: image.size.height/2 - icon.size.height/2, width: icon.size.width, height: icon.size.height), blendMode:CGBlendMode.normal, alpha:1.0) 74 | 75 | let newImage = UIGraphicsGetImageFromCurrentImageContext() 76 | return newImage 77 | } 78 | 79 | /** 80 | Corrects the rotation/orientation of an image. 81 | When an image inadvertently was taken with the wrong orientation, this function will correct the rotation/orientation again. 82 | 83 | - Returns: The orientation corrected image as an `UIImage`. 84 | */ 85 | var rotationCorrected: UIImage? { 86 | 87 | UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) 88 | self.draw(in: CGRect(origin: CGPoint.zero, size: self.size)) 89 | let normalizedImage = UIGraphicsGetImageFromCurrentImageContext() 90 | UIGraphicsEndImageContext() 91 | return normalizedImage 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Codemine/Extensions/UIView+Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Utilities.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public extension UIView { 13 | /** 14 | Assign a `nibName` to a UIView. 15 | Later on you can call this `UIView` by its `nibName`. 16 | 17 | - Parameter name: The name that the UIView will get as its `name` assigned as a `String`. 18 | - Returns: `Generics type`. 19 | */ 20 | static func from(nibWithName:String) -> T? { 21 | let view = UINib(nibName: nibWithName, bundle: nil).instantiate(withOwner: nil, options: nil).first as? T 22 | return view 23 | } 24 | 25 | /** 26 | Rounded corners for a `UIView`. 27 | 28 | - Parameters: 29 | - corners: Defines which corners should be rounded. 30 | - radius: Defines the radius of the round corners as a `CGFloat`. 31 | */ 32 | func roundViewCorners(_ corners:UIRectCorner, radius: CGFloat) { 33 | let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) 34 | let mask = CAShapeLayer() 35 | mask.path = path.cgPath 36 | self.layer.mask = mask 37 | } 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /Codemine/Extensions/URLSession+Codable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLSession+Codable.swift 3 | // Codemine 4 | // 5 | // Created by Andrei Hogea on 22/03/2018. 6 | // Copyright © 2018 Nodes. All rights reserved. 7 | // 8 | 9 | 10 | import Foundation 11 | 12 | // Decoded Result 13 | public enum DResult { 14 | case success(Value) 15 | case successWithError(Value, Error) 16 | case failure(Error) 17 | } 18 | 19 | public extension URLSession { 20 | 21 | /** 22 | Adds a handler that attempts to parse the result of the request into a **Decodable** 23 | 24 | - parameter requestCompletion: The URLSession.dataTask completion 25 | 26 | - returns: The Decoded Result (DResult) 27 | */ 28 | func decode(requestCompletion: (Data?, Error?)) -> DResult { 29 | switch requestCompletion { 30 | case (.some(let data), .some(let error)): 31 | do { 32 | let decodedData = try JSONDecoder().decode(Value.self, from: data) 33 | return .successWithError(decodedData, error) 34 | } catch let decodeError { 35 | return .failure(decodeError) 36 | } 37 | case (.some(let data), .none): 38 | do { 39 | let decodedData = try JSONDecoder().decode(Value.self, from: data) 40 | return .success(decodedData) 41 | } catch let decodeError { 42 | return .failure(decodeError) 43 | } 44 | case (.none, .some(let error)): 45 | return .failure(error) 46 | 47 | case (.none, .none): 48 | let fallBackError = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Data was not retrieved from request"]) as Error 49 | return .failure(fallBackError) 50 | } 51 | } 52 | 53 | /** 54 | Adds a handler that attempts to parse the result of the request into a **Decodable** 55 | 56 | - parameter completion: A closure that is invoked when the request is finished, containting the desired DataModel to be returned 57 | 58 | - returns: The URLSession.dataTask completion 59 | */ 60 | func decode(_ completion: @escaping ((DResult) -> Void)) -> ((Data?, URLResponse?, Error?) -> Void) { 61 | return { (data, _, error) in 62 | DispatchQueue.main.async { 63 | completion(self.decode(requestCompletion: (data, error))) 64 | } 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /Codemine/Operators.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Operators.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreGraphics 11 | 12 | /// Add Operator `+` for two `CGPoints` to summerise them to one `CGPoint`. 13 | public func + (left: CGPoint, right: CGPoint) -> CGPoint { 14 | return CGPoint(x: left.x + right.x, y: left.y + right.y) 15 | } 16 | 17 | /// Add Operator `*` for two `CGPoints` to multiply both with each other to one `CGPoint`. 18 | public func * (left: CGPoint, right: CGPoint) -> CGPoint { 19 | return CGPoint(x: left.x * right.x, y: left.y * right.y) 20 | } 21 | 22 | /// Add Operator `*` to multiply a CGPoint to a CGFloat to get a CGPoint. 23 | public func * (left: CGPoint, right: CGFloat) -> CGPoint { 24 | return CGPoint(x: left.x * right, y: left.y * right) 25 | } 26 | 27 | /// Add Operator `-` for two `CGPoints` subtract the `right` from the `left` `CGPoint`. 28 | public func - (left: CGPoint, right: CGPoint) -> CGPoint { 29 | return CGPoint(x: left.x - right.x, y: left.y - right.y) 30 | } 31 | 32 | /// Add Operator `/` to devide a `CGPoints` by the value of a `CGFloat`. 33 | public func / (left: CGPoint, right: CGFloat) -> CGPoint { 34 | return CGPoint(x: left.x / right, y: left.y / right) 35 | } 36 | 37 | /// Add Operator `/` for two `CGPoints`. The left will be devided by the right one. 38 | public func / (left: CGPoint, right: CGPoint) -> CGPoint { 39 | return CGPoint(x: left.x / right.x, y: left.y / right.y) 40 | } 41 | 42 | /// Add Operator `+` for two `CGSizes` to summerise both to one `CGSize`. 43 | public func + (left: CGSize, right: CGSize) -> CGSize { 44 | return CGSize(width: left.width + right.width, height: left.height + right.height) 45 | } -------------------------------------------------------------------------------- /Codemine/Supporting Files/Codemine.h: -------------------------------------------------------------------------------- 1 | // 2 | // Codemine.h 3 | // Codemine 4 | // 5 | // Created by Chris Combs on 26/01/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Codemine. 12 | FOUNDATION_EXPORT double CodemineVersionNumber; 13 | 14 | //! Project version string for Codemine. 15 | FOUNDATION_EXPORT const unsigned char CodemineVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import -------------------------------------------------------------------------------- /Codemine/Supporting Files/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.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Codemine/Then.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Hyper Interaktiv AS 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining 4 | // a copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to 8 | // permit persons to whom the Software is furnished to do so, subject to 9 | // the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be 12 | // included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | 23 | import Foundation 24 | 25 | public protocol Then {} 26 | extension Then { 27 | 28 | public func then( _ block: (Self) -> Void) -> Self { 29 | block(self) 30 | return self 31 | } 32 | } 33 | 34 | extension NSObject: Then {} 35 | -------------------------------------------------------------------------------- /CodemineTests/CodemineTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodemineTests.swift 3 | // CodemineTests 4 | // 5 | // Created by Chris Combs on 26/01/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Codemine 11 | 12 | class CodemineTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | // MARK: - String Extensions tests 37 | 38 | func testTrueEmailAddress() { 39 | let validEmails = ["TeSt@TesT.COM", "Test@test.com", "email@example.com", "firstname.lastname@example.com", "email@subdomain.example.com", "firstname+lastname@example.com", "1234567890@example.com", "email@example-one.com", "_______@example.com", "email@example.name", "email@example.museum", "email@example.co.jp", "firstname-lastname@example.com"] 40 | for emailAddress in validEmails { 41 | XCTAssertTrue(emailAddress.isValidEmailAddress, "the email address: \(emailAddress) was considered invalid, but it is not") 42 | } 43 | } 44 | 45 | func testFalseEmailAddress() { 46 | let invalidEmails = ["plainaddress", "#@%^%#$@#$@#.com", "@example.com", "Joe Smith ", "email.example.com", "email@example@example.com", ".email@example.com", "email.@example.com", "email..email@example.com", "あいうえお@example.com", "email@example.com (Joe Smith)", "email@example", "email@-example.com", "email@example..com", "Abc..123@example.com"] 47 | for emailAddress in invalidEmails { 48 | XCTAssertFalse(emailAddress.isValidEmailAddress, "the email address: \(emailAddress) was considered valid, but it is not") 49 | } 50 | } 51 | 52 | func testRange() { 53 | let str = "Hello world!" 54 | let range = str.range(from: "e", toString: " w") 55 | XCTAssertTrue(range?.lowerBound == str.index(str.startIndex, offsetBy: 1) && range?.upperBound == str.index(str.startIndex, offsetBy: 7), "range = \(String(describing: range))") 56 | XCTAssertNil(str.range(from: "a", toString: "e")) 57 | XCTAssertNil(str.range(from: "e", toString: "b")) 58 | 59 | XCTAssertNil(str.range(from: "l", toString: "o", searchType: .rightToLeft, inRange: range)) 60 | 61 | let str2 = "abcdefghijklmnopqrstuvwxyz" 62 | let range2 = str2.range(from: "x", toString: "z") 63 | XCTAssertNil(str.range(from: "h", toString: "e", searchType: .leftToRight, inRange: range2)) 64 | 65 | 66 | } 67 | 68 | func testCamerlCaseToUnderscore() { 69 | let snakeCaseStr1 = "user_id" 70 | let camelCaseStr1 = "userId" 71 | let snakeCaseStr2 = "is_user_active_member_of_current_group" 72 | let camelCaseStr2 = "isUserActiveMemberOfCurrentGroup" 73 | 74 | XCTAssertEqual(snakeCaseStr1, camelCaseStr1.camelCaseToUnderscore()) 75 | XCTAssertEqual(snakeCaseStr2, camelCaseStr2.camelCaseToUnderscore()) 76 | } 77 | 78 | 79 | // MARK: - CGRect Extensions tests 80 | 81 | func testX() { 82 | var rect = CGRect(x: 10, y: 10, width: 100, height: 100) 83 | XCTAssertEqual(rect.x, rect.origin.x) 84 | 85 | rect.x = 20 86 | XCTAssertEqual(rect.origin.x, 20) 87 | } 88 | 89 | func testY() { 90 | var rect = CGRect(x: 10, y: 10, width: 100, height: 100) 91 | XCTAssertEqual(rect.y, rect.origin.y) 92 | 93 | rect.y = 20 94 | XCTAssertEqual(rect.origin.y, 20) 95 | } 96 | 97 | func testReversingSize() { 98 | let rect = CGRect(x: 10, y: 10, width: 100, height: 200) 99 | let reversedRect = rect.reversingSize 100 | XCTAssertTrue(rect.size.height == reversedRect.size.width && rect.size.width == reversedRect.size.height) 101 | } 102 | 103 | func testSizeAddition() { 104 | let size1 = CGSize(width: 20, height: 40) 105 | let size2 = CGSize(width: 121, height: 576) 106 | XCTAssertEqual(size1+size2, CGSize(width: size1.width + size2.width, height: size1.height+size2.height)) 107 | } 108 | 109 | // MARK: - CGPoint extension tests 110 | 111 | func testIsClosePoint() { 112 | let point1 = CGPoint(x: 0, y: 0) 113 | let point2 = CGPoint(x: 0, y: 1) 114 | let point3 = CGPoint(x: 1, y: 1) 115 | let point4 = CGPoint(x: 10, y: 10) 116 | XCTAssertTrue(point1.isCloseTo(point2, tolerance: 1)) 117 | XCTAssertFalse(point1.isCloseTo(point2, tolerance: 0.5)) 118 | XCTAssertTrue(point1.isCloseTo(point3, tolerance: 2)) 119 | XCTAssertFalse(point2.isCloseTo(point4, tolerance: 3)) 120 | } 121 | 122 | func testPointAddition() { 123 | let point1 = CGPoint(x: 10, y: 11) 124 | let point2 = CGPoint(x: 2, y: 13) 125 | XCTAssertTrue((point1+point2).x == point1.x + point2.x && (point1+point2).y == point1.y + point2.y) 126 | 127 | } 128 | 129 | func testPointMultiplication() { 130 | let point1 = CGPoint(x: 10, y: 11) 131 | let point2 = CGPoint(x: 2, y: 13) 132 | XCTAssertTrue((point1*point2).x == point1.x * point2.x && (point1*point2).y == point1.y * point2.y) 133 | 134 | } 135 | 136 | func testPointWithScalarMultiplication() { 137 | let point1 = CGPoint(x: 10, y: 11) 138 | let scalar : CGFloat = 4 139 | XCTAssertTrue((point1*scalar).x == point1.x * scalar && (point1*scalar).y == point1.y * scalar) 140 | 141 | } 142 | 143 | func testPointSubtraction() { 144 | let point1 = CGPoint(x: 10, y: 11) 145 | let point2 = CGPoint(x: 2, y: 13) 146 | XCTAssertTrue((point1-point2).x == point1.x - point2.x && (point1-point2).y == point1.y - point2.y) 147 | 148 | } 149 | 150 | func testPointDivision() { 151 | let point1 = CGPoint(x: 10, y: 11) 152 | let point2 = CGPoint(x: 2, y: 13) 153 | XCTAssertTrue((point1/point2).x == point1.x / point2.x && (point1/point2).y == point1.y / point2.y) 154 | 155 | let point3 = CGPoint(x: 0, y: 0) 156 | XCTAssertTrue((point1/point3).x == point1.x / point3.x && (point1/point3).y == point1.y / point3.y) 157 | 158 | } 159 | 160 | func testPointByScalarDivision() { 161 | let point1 = CGPoint(x: 10, y: 11) 162 | let scalar : CGFloat = 4 163 | XCTAssertTrue((point1/scalar).x == point1.x / scalar && (point1/scalar).y == point1.y / scalar) 164 | 165 | let scalar2 : CGFloat = 0 166 | XCTAssertTrue((point1/scalar2).x == point1.x / scalar2 && (point1/scalar2).y == point1.y / scalar2) 167 | 168 | } 169 | 170 | // MARK: - Then test 171 | func testThen() { 172 | let view = UIView().then { 173 | $0.backgroundColor = UIColor.black 174 | $0.alpha = 0.5 175 | } 176 | 177 | XCTAssertEqual(view.alpha, 0.5) 178 | XCTAssertEqual(view.backgroundColor, UIColor.black) 179 | } 180 | 181 | // MARK: - UIColor extension test 182 | func testColor() { 183 | let red = UIColor(rgb: 0xFF0000) 184 | let blue = UIColor(rgb: 0x0000FF) 185 | let magenta = UIColor(rgb: 0xFF00FF) 186 | 187 | XCTAssertEqual(red, UIColor.red) 188 | XCTAssertEqual(blue, UIColor.blue) 189 | XCTAssertEqual(magenta, UIColor.magenta) 190 | XCTAssertNotEqual(red, UIColor.yellow) 191 | } 192 | 193 | func testError() { 194 | let domain = "Domain" 195 | let code = 123 196 | let description = "error description" 197 | let error = NSError(domain: domain, code: code, description: description) 198 | let error2 = NSError(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey : description]) 199 | XCTAssertEqual(error, error2) 200 | } 201 | 202 | // MARK: - XCTestCase extension test 203 | func testThrowsSpecificError() { 204 | //Sample types 205 | enum MyError: Error { 206 | case specificError 207 | } 208 | 209 | func throwIt() throws { 210 | throw MyError.specificError 211 | } 212 | 213 | //Actually test 214 | XCTAssertThrows(try throwIt(), specificError: MyError.specificError) 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /CodemineTests/DispatchTimeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DispatchTimeTests.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 16/12/2016. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class DispatchTimeTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | } 16 | 17 | func testAfterDispatchTime() { 18 | let expectation = self.expectation(description: "The duration should be 3.2 seconds") 19 | 20 | DispatchQueue.main.asyncAfter(deadline: 3.2) { 21 | expectation.fulfill() 22 | } 23 | 24 | waitForExpectations(timeout: 3.2 + 0.005, handler: nil) 25 | 26 | } 27 | 28 | func testAfterIntegerDispatchTime() { 29 | let expectation = self.expectation(description: "The duration should be 3 seconds") 30 | 31 | DispatchQueue.main.asyncAfter(deadline: 3) { 32 | expectation.fulfill() 33 | } 34 | 35 | waitForExpectations(timeout: 3 + 0.005, handler: nil) 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /CodemineTests/Extensions/XCTestCase+Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XCTestCase+Utilities.swift 3 | // Codemine 4 | // 5 | // Created by HE:labs on 18/10/17. 6 | // Copyright © 2017 Nodes. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | extension XCTestCase { 12 | func XCTAssertThrows(_ expression: @autoclosure () throws -> T, specificError: E) where E: Error, E: Equatable { 13 | 14 | XCTAssertThrowsError(try expression()) { error in 15 | XCTAssertEqual(error as? E, specificError) 16 | } 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /CodemineTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /CodemineTests/UIImageTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageTests.swift 3 | // Codemine 4 | // 5 | // Created by Chris on 25/09/2016. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Codemine 11 | 12 | class UIImageTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | func testImageNamed(name: String) -> UIImage { 20 | let bundle = Bundle(for: type(of: self)) 21 | let path = bundle.path(forResource: name, ofType: "png")! 22 | return UIImage(contentsOfFile: path)! 23 | } 24 | 25 | func testUIImageFromColor() { 26 | XCTAssertNotNil(UIImage(color: .red, size: CGSize(width: 20, height: 20), cornerRadius: 1.0), "Failed to convert color to image") 27 | } 28 | 29 | func testImageEmbed() { 30 | XCTAssertNotNil(UIImage.embed(icon: testImageNamed(name: "alert"), inImage: testImageNamed(name: "add")), "Failed to embed image") 31 | } 32 | 33 | func testImageRotation() { 34 | XCTAssertNotNil(testImageNamed(name: "add").rotationCorrected, "Failed to rotate image") 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /CodemineTests/URLImageAssetSizeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLImageAssetSizeTests.swift 3 | // Codemine 4 | // 5 | // Created by Chris on 25/09/2016. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Codemine 11 | 12 | class URLImageAssetSizeTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | 20 | func testURLWithSize() { 21 | guard let url = URL(string: "https://example.com/image.png") else { XCTAssertTrue(false, "Failed to create NSURL"); return } 22 | let size = CGSize(width: 512, height: 256) 23 | let heightParameterName = "height" 24 | let widthParameterName = "width" 25 | 26 | #if os(iOS) || os(tvOS) 27 | let screenScale = UIScreen.main.scale 28 | #else 29 | let screenScale = NSScreen.main?.backingScaleFactor ?? 1.0 30 | #endif 31 | 32 | 33 | let url2 = url.appendingAssetSize(size, mode: .default, heightParameterName: heightParameterName, widthParameterName: widthParameterName) 34 | XCTAssertEqual(url2?.absoluteString, url.absoluteString + "?\(widthParameterName)=\(Int(size.width * screenScale ))&\(heightParameterName)=\(Int(size.height * screenScale))") 35 | 36 | let url3 = url.appendingAssetSize(size) 37 | XCTAssertEqual(url3?.absoluteString, url.absoluteString + "?w=\(Int(size.width * screenScale ))&h=\(Int(size.height * screenScale))") 38 | 39 | let url4 = url.appendingAssetSize(size, mode: .crop) 40 | XCTAssertEqual(url4?.absoluteString, url.absoluteString + "?w=\(Int(size.width * screenScale ))&h=\(Int(size.height * screenScale))&mode=crop") 41 | 42 | } 43 | 44 | func testBadUrl() { 45 | let url = URL(string: "http://example.com:-80/")! 46 | 47 | print(URLComponents(url: url, resolvingAgainstBaseURL: false) ?? "bad value") 48 | 49 | let newUrl = url.appendingAssetSize(CGSize(width: 10, height: 10)) 50 | XCTAssertNil(newUrl?.absoluteString, "Bad URL did not return nil") 51 | } 52 | 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /CodemineTests/URLParameterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLParameterTests.swift 3 | // Codemine 4 | // 5 | // Created by Peter Bødskov on 24/08/2017. 6 | // Copyright © 2017 Nodes. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class URLParameterTests: XCTestCase { 12 | 13 | func testCanFindURLParameter() { 14 | guard let url = URL(string: "https://example.com?param1=value1¶m2=value2") else { 15 | XCTFail("could not create URL") 16 | return 17 | } 18 | 19 | let expectedValue1 = "value1" 20 | guard let actualValue1 = url.value(forParameter: "param1") else { 21 | XCTFail("no value found for parameter") 22 | return 23 | } 24 | XCTAssertTrue(expectedValue1 == actualValue1) 25 | 26 | let expectedValue2 = "value2" 27 | guard let actualValue2 = url.value(forParameter: "param2") else { 28 | XCTFail("no value found for parameter") 29 | return 30 | } 31 | XCTAssertTrue(expectedValue2 == actualValue2) 32 | } 33 | 34 | func testReturnsFirstParameterOfMultipleParametersWithSameName() { 35 | //URL with multiple parameters having the same name but different values (no it shouldn't happen but...) 36 | guard let url = URL(string: "https://example.com?param1=value1¶m1=value2") else { 37 | XCTFail("could not create URL") 38 | return 39 | } 40 | let expectedValue = "value1" 41 | guard let actualValue = url.value(forParameter: "param1") else { 42 | XCTFail("no value found for parameter") 43 | return 44 | } 45 | XCTAssertTrue(expectedValue == actualValue) 46 | } 47 | 48 | func testCanReturnNilForInvalidCases() { 49 | guard let url = URL(string: "https://example.com?param1=value1¶m2=value2") else { 50 | XCTFail("could not create URL") 51 | return 52 | } 53 | XCTAssertNil(url.value(forParameter: "nothere")) 54 | 55 | guard let urlWithNoParameters = URL(string: "https://example.com") else { 56 | XCTFail("could not create URL") 57 | return 58 | } 59 | XCTAssertNil(urlWithNoParameters.value(forParameter: "nothere")) 60 | 61 | } 62 | 63 | func testCanReturnValueFromURLWithTwoParametersWithTheSameName() { 64 | guard let urlWithTwoParametersWithSameName = URL(string: "https://example.com?param1=value1¶m2=value2¶m1=value3") else { 65 | XCTFail("could not create URL") 66 | return 67 | } 68 | 69 | let expectedValue = "value1" 70 | guard let actualValue = urlWithTwoParametersWithSameName.value(forParameter: "param1") else { 71 | XCTFail("no value found for parameter") 72 | return 73 | } 74 | XCTAssertTrue(expectedValue == actualValue) 75 | } 76 | 77 | func testCanAppendQueryParameters() { 78 | guard let url = URL(string: "https://example.com") else { 79 | XCTFail("could not create URL") 80 | return 81 | } 82 | 83 | let expectedValue1 = "value1" 84 | let expectedValue2 = "value2" 85 | 86 | guard let queryParamUrl = url.append(queryParameters: ["param1" : expectedValue1, "param2" : expectedValue2]) else { 87 | XCTFail("could not create queryParamUrl") 88 | return 89 | } 90 | 91 | //Are they even there? 92 | XCTAssertNotNil(queryParamUrl.value(forParameter: "param1")) 93 | XCTAssertNotNil(queryParamUrl.value(forParameter: "param2")) 94 | 95 | //They were, but do they match then? 96 | XCTAssertTrue(queryParamUrl.value(forParameter: "param1")! == expectedValue1) 97 | XCTAssertTrue(queryParamUrl.value(forParameter: "param2")! == expectedValue2) 98 | 99 | } 100 | 101 | func testCanChangeQueryParameters() { 102 | guard let url = URL(string: "http://example.com?token=addtokenhere") else { 103 | XCTFail("could not create URL") 104 | return 105 | } 106 | 107 | let expectedValue = "http://example.com?token=usertoken" 108 | 109 | guard let queryParamUrl = url.changeQueryParamValue(withName: "token", to: "usertoken") else { 110 | XCTFail("could not change queryParamUrl") 111 | return 112 | } 113 | 114 | //Is the param even there? 115 | XCTAssertNotNil(queryParamUrl.value(forParameter: "token")) 116 | 117 | //It is, but does it match? 118 | XCTAssertTrue(queryParamUrl.absoluteString == expectedValue) 119 | } 120 | 121 | func testChangeQueryParametersWithWrongInput() { 122 | guard let url = URL(string: "http://example.com?token=addtokenhere") else { 123 | XCTFail("could not create URL") 124 | return 125 | } 126 | 127 | //Trying with a queryparam that's not in the url - expecting nil 128 | XCTAssertNil(url.changeQueryParamValue(withName: "username", to: "usertoken")) 129 | 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /CodemineTests/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/Codemine/10ed08cf0ec1a8eb3390b8d79cd3084d30086e9c/CodemineTests/add.png -------------------------------------------------------------------------------- /CodemineTests/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/Codemine/10ed08cf0ec1a8eb3390b8d79cd3084d30086e9c/CodemineTests/alert.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Nodes Agency - iOS 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. -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Package.swift 3 | // Codemine 4 | // 5 | // Created by Marius Constantinescu on 18/02/16. 6 | // Copyright © 2016 Nodes. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import PackageDescription 12 | let package = Package( 13 | name: "Codemine" 14 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Codemine 2 | [![CircleCI](https://circleci.com/gh/nodes-ios/Codemine.svg?style=shield)](https://circleci.com/gh/nodes-ios/Codemine) 3 | [![Codecov](https://img.shields.io/codecov/c/github/nodes-ios/Codemine.svg)](https://codecov.io/github/nodes-ios/Codemine) 4 | [![CocoaPods](https://img.shields.io/cocoapods/v/Codemine.svg)](https://cocoapods.org/pods/Codemine) 5 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 6 | ![Swift Package Manager](https://img.shields.io/badge/SPM-compatible-brightgreen.svg) 7 | ![Plaform](https://img.shields.io/badge/platform-iOS-lightgrey.svg) 8 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/nodes-ios/Codemine/blob/master/LICENSE) 9 | [![Readme Score](http://readme-score-api.herokuapp.com/score.svg?url=nodes-ios/codemine)](http://clayallsopp.github.io/readme-score?url=nodes-ios/codemine) 10 | 11 | Codemine is a collection of extensions containing useful functions and syntactic sugar for your Swift project. 12 | 13 | 14 | ## Table of contents 15 | **Using Codemine as a library** 16 | 17 | - [Requirements](#requirements) 18 | - [Installation](#installation) 19 | 20 | **Browsing the individual code snippets and usages.** 21 | 22 | - [Application](#application) 23 | - [CGPoint](#cgpoint) 24 | - [CGRect](#cgrect) 25 | - [Dispatch time](#dispatch-time) 26 | - [Hex initializable](#hex-initializable) 27 | - [NSError](#nserror) 28 | - [String](#string) 29 | - [String initializable](#string-initializable) 30 | - [UIImage](#uiimage) 31 | - [UIView](#uiview) 32 | - [URL](#url) 33 | - [URLSession](#urlsession) 34 | 35 | **Other** 36 | 37 | - [Credits](#credits) 38 | - [License](#license) 39 | 40 | ## Requirements 41 | 42 | * iOS 8.0+ 43 | * Swift 3.0+ 44 | 45 | 46 | ## Installation 47 | 48 | ### CocoaPods 49 | 50 | If you are using CocoaPods add this text to your Podfile and run `pod install`. 51 | 52 | ~~~ 53 | pod 'Codemine', '~>1.0.0' 54 | 55 | # Swift 2.3 56 | pod 'Codemine', '~>0.2.5' 57 | 58 | # Swift 2.2 59 | pod 'Codemine', '~>0.2.2' 60 | ~~~ 61 | 62 | ### Carthage 63 | ~~~ 64 | github "nodes-ios/Codemine" ~> 1.0 65 | 66 | # Swift 2.3 67 | github "nodes-ios/Codemine" == 0.2.5 68 | 69 | # Swift 2.2 70 | github "nodes-ios/Codemine" == 0.2.2 71 | ~~~ 72 | 73 | ## Application 74 | ### Description 75 | Contains easily accessible variables for the application's: 76 | 77 | - Display name 78 | - Version number 79 | - Build number 80 | - Executable name 81 | - Bundle identifier 82 | - Available schemes 83 | - Main scheme 84 | 85 | ### Code 86 | ```swift 87 | public struct Application { 88 | 89 | fileprivate static func getString(_ key: String) -> String { 90 | guard let infoDictionary = Bundle.main.infoDictionary, 91 | let value = infoDictionary[key] as? String 92 | else { return "" } 93 | 94 | return value 95 | } 96 | 97 | public static var name: String = { 98 | return Application.getString("CFBundleDisplayName") 99 | }() 100 | 101 | public static var version: String = { 102 | return Application.getString("CFBundleShortVersionString") 103 | }() 104 | 105 | public static var build: String = { 106 | return Application.getString("CFBundleVersion") 107 | }() 108 | 109 | public static var executable: String = { 110 | return Application.getString("CFBundleExecutable") 111 | }() 112 | 113 | public static var bundle: String = { 114 | return Application.getString("CFBundleIdentifier") 115 | }() 116 | 117 | public static var schemes: [String] = { 118 | guard let infoDictionary = Bundle.main.infoDictionary, 119 | let urlTypes = infoDictionary["CFBundleURLTypes"] as? [AnyObject], 120 | let urlType = urlTypes.first as? [String : AnyObject], 121 | let urlSchemes = urlType["CFBundleURLSchemes"] as? [String] 122 | else { return [] } 123 | 124 | return urlSchemes 125 | }() 126 | 127 | public static var mainScheme: String? = { 128 | return schemes.first 129 | }() 130 | } 131 | ``` 132 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Application.swift) 133 | ### 💻 Usage 134 | ```swift 135 | let appName = Application.name // CFBundleDisplayName : String 136 | let appVersion = Application.version // CFBundleShortVersionString : String 137 | let appExecutable = Application.executable // CFBundleExecutable : String 138 | let appBundle = Application.bundle // CFBundleIdentifier : String 139 | let appSchemes = Application.schemes // CFBundleURLSchemes : [String] 140 | let mainAppScheme = Application.mainScheme // CFBundleURLSchemes.first : String? 141 | ``` 142 | 143 | ## CGPoint 144 | ### Description 145 | Contains methods: 146 | 147 | - `isCloseTo` which checks if a CGPoint is close to another CGPoint within a given tolerance. 148 | 149 | Constains operators: 150 | 151 | - `+` which summerises 2 `CGPoints` into 1 152 | - `*` which multiplies 2 `CGPoints` with each other to 1 `CGPoint` 153 | - `*` which multiplies a `CGPoint`'s `x` and `y` value with a `CGFloat` 154 | - `-` which subtracts the right `CGPoint` from the left `CGPoint` 155 | - `/` which devides a `CGPoint`'s `x` and `y` value by a `CGFloat` 156 | - `/` which devides 2 `CGPoints` by each other to 1 `CGPoint` 157 | 158 | ### Code 159 | #### Extension 160 | ```swift 161 | import CoreGraphics 162 | 163 | public extension CGPoint { 164 | /** 165 | Check if a `CGPoint` is close to another `CGPoint`. 166 | There is a tolerance that defines the range that is tolerated to call it close to another `CGPoint`. 167 | If the actual point is close to the `point` from the parameter it will return true. 168 | 169 | - Parameters: 170 | - point: The `CGPoint` that will be checked if it is close to the actual `CGPoint`. 171 | - tolerance: Defines what range is tolerated to be close to the other `point`. 172 | 173 | - Returns: `Boolean` - if close to return true, else false. 174 | */ 175 | func isCloseTo(_ point: CGPoint, tolerance: CGFloat) -> Bool { 176 | let xIsClose = self.x <= point.x + tolerance && self.x >= point.x - tolerance 177 | let yIsClose = self.y <= point.y + tolerance && self.y >= point.y - tolerance 178 | return xIsClose && yIsClose 179 | } 180 | } 181 | ``` 182 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/CGPoint%2BUtilities.swift) 183 | #### Operators 184 | ```swift 185 | import CoreGraphics 186 | 187 | /// Add Operator `+` for two `CGPoints` to summerise them to one `CGPoint`. 188 | public func + (left: CGPoint, right: CGPoint) -> CGPoint { 189 | return CGPoint(x: left.x + right.x, y: left.y + right.y) 190 | } 191 | 192 | /// Add Operator `*` for two `CGPoints` to multiply both with each other to one `CGPoint`. 193 | public func * (left: CGPoint, right: CGPoint) -> CGPoint { 194 | return CGPoint(x: left.x * right.x, y: left.y * right.y) 195 | } 196 | 197 | /// Add Operator `*` to multiply a CGPoint to a CGFloat to get a CGPoint. 198 | public func * (left: CGPoint, right: CGFloat) -> CGPoint { 199 | return CGPoint(x: left.x * right, y: left.y * right) 200 | } 201 | 202 | /// Add Operator `-` for two `CGPoints` subtract the `right` from the `left` `CGPoint`. 203 | public func - (left: CGPoint, right: CGPoint) -> CGPoint { 204 | return CGPoint(x: left.x - right.x, y: left.y - right.y) 205 | } 206 | 207 | /// Add Operator `/` to devide a `CGPoints` by the value of a `CGFloat`. 208 | public func / (left: CGPoint, right: CGFloat) -> CGPoint { 209 | return CGPoint(x: left.x / right, y: left.y / right) 210 | } 211 | 212 | /// Add Operator `/` for two `CGPoints`. The left will be devided by the right one. 213 | public func / (left: CGPoint, right: CGPoint) -> CGPoint { 214 | return CGPoint(x: left.x / right.x, y: left.y / right.y) 215 | } 216 | ``` 217 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Operators.swift) 218 | ### 💻 Usage 219 | ```swift 220 | let point1 = CGPoint(x: 5, y: 5) 221 | let point2 = CGPoint(x: 5, y: 6) 222 | print(point1.isCloseTo(point2, tolerance: 1)) // true 223 | print(point1.isCloseTo(point2, tolerance: 0.5)) // false 224 | print(point1+point2) // (10, 11) 225 | print(point1*point2) // (25, 30) 226 | print(point1*2) // (10, 10) 227 | print(point1-point2) // (0, -1) 228 | print(point1/point2) // (1, 0.83) 229 | print(point1/5) // (1, 1) 230 | ``` 231 | 232 | ## CGRect 233 | ### Description 234 | Contains variables: 235 | 236 | - `y` which returns and sets `origin.y` 237 | - `x` which returns and sets `origin.x` 238 | - `reversingSize` which returns a `CGRect` with height and width swapped 239 | 240 | ### Code 241 | ```swift 242 | import CoreGraphics 243 | 244 | public extension CGRect { 245 | /// Getter & Setter for a `CGRect`'s `origin.y` 246 | public var y: CGFloat { 247 | set { 248 | self = CGRect(origin: CGPoint(x: origin.x, y: newValue), size: size) 249 | } 250 | get { 251 | return self.origin.y 252 | } 253 | } 254 | 255 | /// Getter & Setter for a `CGRect`s `origin.x` 256 | public var x: CGFloat { 257 | set { 258 | self = CGRect(origin: CGPoint(x: newValue, y: origin.y), size: size) 259 | } 260 | get { 261 | return self.origin.x 262 | } 263 | } 264 | 265 | /** 266 | Reverses the width and height of a 'CGRect' 267 | 268 | - returns: a new CGRect with the width and height reversed to those of the current one 269 | */ 270 | public var reversingSize: CGRect { 271 | return CGRect(origin: origin, size: CGSize(width: height, height: width)) 272 | } 273 | } 274 | ``` 275 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/CGRect%2BUtilities.swift) 276 | ### 💻 Usage 277 | ```swift 278 | var rect = CGRect(x: 10, y: 10, width: 120, height: 100) 279 | rect.x = 50 280 | print(rect) // outputs x:50, y:20, width: 120, height:100 281 | rect.y = -10 282 | print(rect) // outputs x:50, y:-10, width: 120, height:100 283 | let reversedRect = rect.reversingSize 284 | print(reversedRect) // outputs x:50, y:-10, width:100, height:120 285 | ``` 286 | 287 | ## CGSize 288 | ### Description 289 | Contains operators: 290 | 291 | - `+` which summerises both `CGSizes` into 1 292 | 293 | ### Code 294 | ```swift 295 | /// Add Operator `+` for two `CGSizes` to summerise both to one `CGSize`. 296 | public func + (left: CGSize, right: CGSize) -> CGSize { 297 | return CGSize(width: left.width + right.width, height: left.height + right.height) 298 | } 299 | ``` 300 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Operators.swift) 301 | ### 💻 Usage 302 | ```swift 303 | var size = CGSize(width: 5, height: 10) 304 | var size2 = CGSize(width: 10, height: 20) 305 | 306 | print(size) // (5.0, 10.0) 307 | print(size2) // (10.0, 20.0) 308 | print(size+size2) // (15.0, 30.0) 309 | ``` 310 | 311 | ## Dispatch time 312 | ### Description 313 | Contains initializers: 314 | 315 | - `init(integerLiteral:)` which adds the given value `Int` as a delay in seconds 316 | - `init(floatLiteral:` which adds the given `Double` as a delay in seconds and fractions of seconds 317 | 318 | ### Code 319 | ```swift 320 | // Credits for this go to Russ Bishop http://www.russbishop.net/quick-easy-dispatchtime 321 | 322 | extension DispatchTime: ExpressibleByIntegerLiteral { 323 | public init(integerLiteral value: Int) { 324 | self = DispatchTime.now() + .seconds(value) 325 | } 326 | } 327 | 328 | extension DispatchTime: ExpressibleByFloatLiteral { 329 | public init(floatLiteral value: Double) { 330 | self = DispatchTime.now() + .milliseconds(Int(value * 1000)) 331 | } 332 | } 333 | ``` 334 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/DispatchTime%2BUtilities.swift) 335 | ### 💻 Usage 336 | ```swift 337 | DispatchQueue.main.asyncAfter(deadline: 5) { /* ... */ } 338 | ``` 339 | 340 | ## Hex initializable 341 | ### Description 342 | Contains methods: 343 | 344 | - `fromHexString(hexString: String) -> String` which converts a hex string to a usable UIColor. 345 | 346 | ### Code 347 | ```swift 348 | import UIKit 349 | 350 | public protocol HexInitializable { 351 | static func fromHexString(_ hexString: String) -> T? 352 | } 353 | 354 | extension UIColor: HexInitializable { 355 | 356 | public static func fromHexString(_ hexString: String) -> T? { 357 | let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) 358 | var int = UInt32() 359 | let a, r, g, b: UInt32 360 | 361 | guard Scanner(string: hex).scanHexInt32(&int) else { 362 | return nil 363 | } 364 | 365 | switch hex.count { 366 | // RGB (12-bit) 367 | case 3: 368 | (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) 369 | // RRGGBB (24-bit) 370 | case 6: 371 | (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) 372 | // ARGB (32-bit) 373 | case 8: 374 | (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) 375 | default: 376 | return nil 377 | } 378 | 379 | return self.init(red: CGFloat(r) / 255, 380 | green: CGFloat(g) / 255, 381 | blue: CGFloat(b) / 255, 382 | alpha: CGFloat(a) / 255) as? T 383 | } 384 | } 385 | 386 | ``` 387 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/Extention%2BHexInitializable.swift) 388 | ### 💻 Usage 389 | ```swift 390 | var color: UIColor? = UIColor.fromHexString("7353BA") 391 | ``` 392 | 393 | ## NSError 394 | ### Description 395 | Contains convenience initializers: 396 | 397 | - `init(domain: String, code: Int, description: String)` which facilitates the initialization on a NSError object. 398 | 399 | ### Code 400 | ```swift 401 | public extension NSError { 402 | /** 403 | Convenience initializer for an NSError 404 | 405 | - parameter domain: The error domain—this can be one of the predefined NSError domains, or an arbitrary string describing a custom domain. domain must not be nil. 406 | - parameter code: The error code for the error. 407 | - parameter description: The description of the error. Corresponds to the `NSLocalizedDescriptionKey` in the 'userInfo' dictionary 408 | 409 | - returns: An NSError object initialized for domain with the specified error code and the description. 410 | */ 411 | convenience init(domain: String, code: Int, description: String) { 412 | self.init(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey : description]) 413 | } 414 | } 415 | ``` 416 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/NSError%2BUtilities.swift) 417 | ### 💻 Usage 418 | ```swift 419 | let error = NSError(domain: domain, code: code, description: description) 420 | ``` 421 | Instead of 422 | 423 | ```swift 424 | let error = NSError(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey : description]) 425 | ``` 426 | 427 | ## String 428 | ### Description 429 | Contains variables: 430 | 431 | - `isValidEmailAddress` which returns true if the string conforms to the email Regex 432 | - `attributedHTMLString` which returns the attributed HTML string(from stringFromHtml) for the current String 433 | 434 | Contains methods: 435 | 436 | - `camelCaseToUnderscore` which turns a camelCasedString to a snake_cased_string 437 | - `range(fromString: String, toString)` which returns the range between 2 given strings. 438 | - `stringFromHtml(string: String)` which takes an HTML string and returns an Attributes string with the HTML attributes. 439 | 440 | ### Code 441 | #### General 442 | ```swift 443 | public extension String { 444 | /** 445 | Returns a snake_case String based on the current camelCase string. For example, userId will be transformed into user_id 446 | 447 | - returns: the snake_case String 448 | */ 449 | public func camelCaseToUnderscore() -> String { 450 | var returnString = self 451 | 452 | let characterArray = Array(returnString.characters).map { (character) -> String in 453 | let inputCharacterString = String(character) 454 | let lowerCaseCharacterString = String(character).lowercased() 455 | 456 | if inputCharacterString != lowerCaseCharacterString { 457 | return "_" + lowerCaseCharacterString 458 | } 459 | 460 | return inputCharacterString 461 | } 462 | 463 | returnString = characterArray.reduce("") { 464 | return $0 + $1 465 | } 466 | 467 | return returnString 468 | } 469 | 470 | /** 471 | Checks if the current string is a valid email address. 472 | 473 | - returns: true is the current string is a valid email address, false otherwise 474 | */ 475 | public var isValidEmailAddress: Bool { 476 | 477 | let emailRegex = "\\A[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\z" 478 | let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegex) 479 | return emailTest.evaluate(with: self) 480 | } 481 | } 482 | ``` 483 | [See "CamelCaseToUnderscore" in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/String%2BCaseConverter.swift) 484 | [See "isValidEmailAddress" in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/String%2BEmailValidation.swift) 485 | #### Range 486 | ```swift 487 | public extension String { 488 | /** 489 | Checks if a range appears in a String. 490 | 491 | - parameter range: the range that is checked 492 | 493 | - returns: true if the string contains that range, false otherwise 494 | */ 495 | private func contains(_ range: Range) -> Bool { 496 | if range.lowerBound < self.startIndex || range.upperBound > self.endIndex { 497 | return false 498 | } 499 | 500 | return true 501 | } 502 | 503 | public enum RangeSearchType: Int { 504 | case leftToRight 505 | case rightToLeft 506 | case broadest 507 | case narrowest 508 | } 509 | 510 | /** 511 | Returns the range between two substrings, including the 2 substrings. 512 | 513 | - parameter string: first substring 514 | - parameter toString: second substring 515 | - parameter searchType: direction of search 516 | - parameter inRange: the range of the string in which the search is performed. If nil, it will be done in the whole string. 517 | 518 | - returns: the range between the start of the first substring and the end of the last substring 519 | */ 520 | public func range(from fromString: String, toString: String, searchType: RangeSearchType = .leftToRight, inRange: Range? = nil) -> Range? { 521 | let range = inRange ?? Range(uncheckedBounds: (lower: self.startIndex, upper: self.endIndex)) 522 | if !contains(range) { return nil } 523 | 524 | guard let firstRange = self.range(of: fromString, options: NSString.CompareOptions(rawValue: 0), range: range, locale: nil) else { return nil } 525 | guard let secondRange = self.range(of: toString, options: NSString.CompareOptions(rawValue: 0), range: range, locale: nil) else { return nil } 526 | 527 | switch searchType { 528 | case .leftToRight: 529 | return firstRange.lowerBound.. NSAttributedString? { 545 | do { 546 | let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true) 547 | if let d = data { 548 | let str = try NSAttributedString(data: d, 549 | options: [ 550 | NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html, 551 | NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue], 552 | documentAttributes: nil) 553 | return str 554 | } 555 | } catch { 556 | print(error) 557 | } 558 | return nil 559 | } 560 | 561 | extension UILabel { 562 | public convenience init(htmlString: String) { 563 | self.init() 564 | numberOfLines = 0 565 | lineBreakMode = .byWordWrapping 566 | attributedText = htmlString.attributedHTMLString 567 | } 568 | } 569 | 570 | extension String { 571 | public var attributedHTMLString: NSAttributedString? { 572 | return stringFromHtml(string: self) 573 | } 574 | } 575 | ``` 576 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/String%2BHTML.swift) 577 | ### 💻 Usage 578 | #### General 579 | ```swift 580 | let camelCaseStr1 = "userId" 581 | let camelCaseStr2 = "isUserActiveMemberOfCurrentGroup" 582 | 583 | print(camelCaseStr1.camelCaseToUnderscore()) // "user_id" 584 | print(camelCaseStr2.camelCaseToUnderscore()) // "is_user_active_member_of_current_group" 585 | 586 | "email@example.com".isValidEmailAddress() // true 587 | "email.example.com".isValidEmailAddress() // false 588 | ``` 589 | #### Range 590 | ```swift 591 | let str = "Hello world!" 592 | let range = str.range(from: "e", toString: " w") // Range(1..<7) 593 | ``` 594 | #### HTML 595 | ```swift 596 | let htmlString = """ 597 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit

598 | 599 |

Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

600 | 601 |

Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta del veritas.

602 | """ 603 | 604 | // Initialize new attributed string 605 | let attributedString = stringFromHtml(string: htmlString) 606 | 607 | // Access attributed string from original 608 | print(htmlString.attributedHTMLString) 609 | 610 | // Initialize label with html string 611 | let attributedLabel = UILabel(htmlString: htmlString) 612 | ``` 613 | 614 | 615 | ## String initializable 616 | ### Description 617 | A protocol that contains methods: 618 | 619 | - `fromString(string: String) -> T?` which should initialize the conformed class using a `String` 620 | - `stringRepresentation() -> String` which returns a `String` representation of the conformed class. 621 | 622 | 623 | Contains extensions to `URL` and `Date` to get a `URL` or `Date` from a `String` and get its `String` representation. 624 | ### Code 625 | 626 | ```swift 627 | public protocol StringInitializable { 628 | static func fromString(_ string: String) -> T? 629 | func stringRepresentation() -> String 630 | } 631 | 632 | extension URL: StringInitializable { 633 | public static func fromString(_ string: String) -> T? { 634 | return self.init(string: string) as? T 635 | } 636 | 637 | public func stringRepresentation() -> String { 638 | return self.absoluteString 639 | } 640 | } 641 | 642 | extension Date: StringInitializable { 643 | static fileprivate let internalDateFormatter = DateFormatter() 644 | static fileprivate let allowedDateFormats = ["yyyy-MM-dd'T'HH:mm:ssZZZZZ", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd"] 645 | static public var customDateFormats: [String] = [] 646 | 647 | public static func fromString(_ string: String) -> T? { 648 | for format in allowedDateFormats + customDateFormats { 649 | internalDateFormatter.dateFormat = format 650 | if let date = internalDateFormatter.date(from: string) as? T { 651 | return date 652 | } 653 | } 654 | 655 | return nil 656 | } 657 | 658 | public func stringRepresentation() -> String { 659 | Date.internalDateFormatter.dateFormat = Date.allowedDateFormats.first 660 | return Date.internalDateFormatter.string(from: self) 661 | } 662 | } 663 | ``` 664 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/Extensions%2BStringInitializable.swift) 665 | ### 💻 Usage 666 | ```swift 667 | let urlFromString: URL? = URL.fromString("https://www.google.com") 668 | 669 | print(urlFromString?.stringRepresentation()) // Optional("https://www.google.com") 670 | 671 | let dateFromString: Date? = Date.fromString("2019-04-15") 672 | 673 | print(dateFromString?.stringRepresentation()) // Optional("2019-04-15T00:00:00+02:00") 674 | ``` 675 | 676 | ## UIImage 677 | ### Description 678 | Contains initializers: 679 | 680 | - `init(color: UIColor, size: CGSize, cornerRadius: CGFloat)` which initializes a `UIImage` with a given size, filled with the given color. 681 | 682 | Contains variables: 683 | 684 | - `rotationCorrected` which corrects the orientation of the `UIImage` 685 | 686 | Contains methods: 687 | 688 | - `embed(icon: UIImage, inImage: UIImage) -> UIImage` which embeds the `icon` ontop of the given `image` 689 | 690 | ### Code 691 | ```swift 692 | import UIKit 693 | 694 | public extension UIImage { 695 | /** 696 | Create an `UIImage` with specified background color, size and corner radius. 697 | 698 | Parameter `color` is used for the background color, 699 | parameter `size` to set the size of the the holder rectangle, 700 | parameter `cornerRadius` for setting up the rounded corners. 701 | 702 | - Parameters: 703 | - color: The background color. 704 | - size: The size of the image. 705 | - cornerRadius: The corner radius. 706 | 707 | - Returns: A 'UIImage' with the specified color, size and corner radius. 708 | */ 709 | 710 | convenience init(color: UIColor, size: CGSize, cornerRadius: CGFloat) { 711 | self.init() 712 | 713 | /// The base rectangle of the image. 714 | let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) 715 | UIGraphicsBeginImageContext(rect.size) 716 | 717 | /// The graphics context of the image. 718 | let context = UIGraphicsGetCurrentContext() 719 | context?.setFillColor(color.cgColor) 720 | context?.fill(rect) 721 | 722 | /// Image that will be retured. 723 | var image = UIGraphicsGetImageFromCurrentImageContext() 724 | UIGraphicsEndImageContext() 725 | 726 | UIGraphicsBeginImageContext(size) 727 | 728 | UIBezierPath(roundedRect: rect, cornerRadius:cornerRadius).addClip() 729 | image?.draw(in: rect) 730 | 731 | image = UIGraphicsGetImageFromCurrentImageContext() 732 | UIGraphicsEndImageContext() 733 | } 734 | 735 | 736 | /** 737 | Embed an icon/image on top of a background image. 738 | 739 | `image` will be the background and `icon` is the image that will be on top of `image`. 740 | The `UIImage` that is set with the parameter `icon` will be centered on `image`. 741 | 742 | - Parameters: 743 | - icon: The embedded image that will be on top. 744 | - image: The background image. 745 | - Returns: The combined image as `UIImage`. 746 | */ 747 | public class func embed(icon: UIImage, inImage image: UIImage ) -> UIImage? { 748 | let newSize = CGSize(width: image.size.width, height: image.size.height) 749 | UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0) 750 | 751 | image.draw(in: CGRect(x: 0,y: 0,width: newSize.width,height: newSize.height)) 752 | 753 | // Center icon 754 | icon.draw(in: CGRect(x: image.size.width/2 - icon.size.width/2, y: image.size.height/2 - icon.size.height/2, width: icon.size.width, height: icon.size.height), blendMode:CGBlendMode.normal, alpha:1.0) 755 | 756 | let newImage = UIGraphicsGetImageFromCurrentImageContext() 757 | return newImage 758 | } 759 | 760 | /** 761 | Corrects the rotation/orientation of an image. 762 | When an image inadvertently was taken with the wrong orientation, this function will correct the rotation/orientation again. 763 | 764 | - Returns: The orientation corrected image as an `UIImage`. 765 | */ 766 | public var rotationCorrected: UIImage? { 767 | 768 | UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) 769 | self.draw(in: CGRect(origin: CGPoint.zero, size: self.size)) 770 | let normalizedImage = UIGraphicsGetImageFromCurrentImageContext() 771 | UIGraphicsEndImageContext() 772 | return normalizedImage 773 | } 774 | } 775 | ``` 776 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/UIImage%2BUtilities.swift) 777 | ### 💻 Usage 778 | 779 | ```swift 780 | let image = UIImage(color: UIColor.red, CGSize(width: 512, height: 256), cornerRadius:4.0) 781 | ``` 782 | Returns a `UIImage` filled with red color, of the specified size and with the specified corner radius 783 | 784 | ```swift 785 | let image = UIImage.embed(icon: UIImage(named:"favouriteIcon"), inImage: UIImage(named:"profilePhoto")) 786 | ``` 787 | Returns a `UIImage` composed by overlaying the icon on top of the first image. 788 | 789 | ## UIView 790 | ### Description 791 | Contains methods: 792 | 793 | - `from(nibWithName: String) -> T?` which returns `UIView` initialized from a nib with the given nibName 794 | - `roundViewCorners(corners: UIRectCorner, radius: CGFloat)` which rounds the current views given corners using the `layer.mask` approach 795 | 796 | ### Code 797 | ```swift 798 | import UIKit 799 | 800 | public extension UIView { 801 | /** 802 | Assign a `nibName` to a UIView. 803 | Later on you can call this `UIView` by its `nibName`. 804 | 805 | - Parameter name: The name that the UIView will get as its `name` assigned as a `String`. 806 | - Returns: `Generics type`. 807 | */ 808 | public static func from(nibWithName:String) -> T? { 809 | let view = UINib(nibName: nibWithName, bundle: nil).instantiate(withOwner: nil, options: nil).first as? T 810 | return view 811 | } 812 | 813 | /** 814 | Rounded corners for a `UIView`. 815 | 816 | - Parameters: 817 | - corners: Defines which corners should be rounded. 818 | - radius: Defines the radius of the round corners as a `CGFloat`. 819 | */ 820 | public func roundViewCorners(_ corners:UIRectCorner, radius: CGFloat) { 821 | let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) 822 | let mask = CAShapeLayer() 823 | mask.path = path.cgPath 824 | self.layer.mask = mask 825 | } 826 | } 827 | ``` 828 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/UIView%2BUtilities.swift) 829 | ### 💻 Usage 830 | ```swift 831 | let view = UIView.from(nibWithName("customView")) 832 | ``` 833 | Returns a view instantiated from the specified nib. 834 | 835 | ```swift 836 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20)) 837 | view.roundViewCorners(UIRectCorner.allCorners, radius: 4.0) 838 | ``` 839 | Rounds the specified corners of a `UIView` to the specified radius. 840 | 841 | ## URL 842 | ### Description 843 | Contains methods: 844 | 845 | - `appendingAssetSize(size: CGSize, mode: ImageUrlMode, heightParameterName: String, widthParameterName: String) -> URL?` which Adds the height, wifth and mode parameters to an URL 846 | - `value(forParameter: String) -> String?` which finds the first value for a URL parameter in a `URL` 847 | - `append(queryParameters: [String: String]) -> URL?` which appends the given parameters to the `URL` 848 | 849 | ### Code 850 | ```swift 851 | import CoreGraphics 852 | import UIKit 853 | 854 | public extension URL { 855 | /** 856 | Mode for image urls. 857 | It defines in which mode an image will be provided. 858 | 859 | - Resize: Resize image mode. The image can be streched or compressed. 860 | - Crop: Cropped image mode. It will crop into an image so only a part of the image will be provided. 861 | If no value is explicitly set, the default behavior is to center the image. 862 | - Fit: Resizes the image to fit within the width and height boundaries without cropping or distorting the image. 863 | The resulting image is assured to match one of the constraining dimensions, 864 | while the other dimension is altered to maintain the same aspect ratio of the input image. 865 | - Standard: Default/normal image mode. No changes to the ratio. 866 | */ 867 | public enum ImageUrlMode : String { 868 | case resize = "resize" 869 | case crop = "crop" 870 | case fit = "fit" 871 | case `default` = "default" 872 | } 873 | 874 | /** 875 | Adds height, width and mode paramters to an url. To be used when fetching an image from a CDN, for example. 876 | Choose the `size` and the `mode` for the image url to define how an image will be provided from the backend. 877 | 878 | - parameters: 879 | - size: Set `size` as `CGSize` to define the size of the image that will be provided. 880 | - mode: Select a mode from predefined `ImageUrlMode` to set up a mode and define how an image will be provided. 881 | - heightParameterName: the name of the height paramter. Default is 'h' 882 | - widthParameterName: the name of the width paramter. Default is 'h' 883 | - returns: `URL` as a `NSURL`. 884 | */ 885 | public func appendingAssetSize(_ size: CGSize, mode: ImageUrlMode = .default, heightParameterName : String = "h", widthParameterName : String = "w") -> URL? { 886 | guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: false) else { return nil } 887 | 888 | var queryItems:[URLQueryItem] = urlComponents.queryItems ?? [] 889 | queryItems.append(URLQueryItem(name: widthParameterName, value: "\(Int(size.width * UIScreen.main.scale ))")) 890 | queryItems.append(URLQueryItem(name: heightParameterName, value: "\(Int(size.height * UIScreen.main.scale ))")) 891 | if mode != .default { 892 | queryItems.append(URLQueryItem(name: "mode", value: mode.rawValue)) 893 | } 894 | urlComponents.queryItems = queryItems 895 | return urlComponents.url 896 | } 897 | 898 | /** 899 | Finds the first value for a URL parameter in a `URL` 900 | - parameters: 901 | - name: the URL parameter to look for 902 | - returns: the first value found for `name` or nil if no value was found 903 | */ 904 | public func value(forParameter name: String) -> String? { 905 | guard let urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: true), 906 | let queryItems = urlComponents.queryItems else { 907 | return nil 908 | } 909 | let items = queryItems.filter({ $0.name == name }) 910 | return items.first?.value 911 | } 912 | 913 | /** 914 | Appends queryParameters to a `URL` 915 | - parameters: 916 | - queryParameters: a `String` : `String` dictionary containing the queryParameters to append 917 | - returns: a new `URL` instance with the appended queryParameters or nil if the appending failed 918 | */ 919 | public func append(queryParameters: [String: String]) -> URL? { 920 | guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: true) else { 921 | return nil 922 | } 923 | 924 | let urlQueryItems = queryParameters.map{ 925 | return URLQueryItem(name: $0, value: $1) 926 | } 927 | urlComponents.queryItems = urlQueryItems 928 | return urlComponents.url 929 | } 930 | } 931 | ``` 932 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/NSURL%2BUtilities.swift) 933 | ### 💻 Usage 934 | ```swift 935 | guard let url = NSURL(string: "https://example.com/image.png") else { return } 936 | let size = CGSize(width: 512, height: 256) 937 | let heightParameterName = "height" 938 | let widthParameterName = "width" 939 | 940 | let url2 = url.appendingAssetSize(size, mode: .default, heightParameterName: heightParameterName, widthParameterName: widthParameterName) 941 | print(url2.absoluteString) // on an @2x screen: "https://example.com/image.png?width=1024&height=512" 942 | ``` 943 | This method appends the `size` multiplied by `UIScreen.main.scale` to an asset url so that the asset has the correct size to be shown on the screen. 944 | 945 | 946 | ## URLSession 947 | ### Description 948 | Contains methods: 949 | 950 | - `decode(requestCompletion: (Data?, Error?)) -> DResult` which adds a handler that attempts to parse the result of the request into a `Decodable` 951 | - `decode(_ completion: @escaping ((DResult) -> Void)) -> ((Data?, URLResponse?, Error?) -> Void)` which adds a handler that attempts to parse the requst of the request into a `Decodable` 952 | 953 | ### Code 954 | ```swift 955 | // Decoded Result 956 | public enum DResult { 957 | case success(Value) 958 | case successWithError(Value, Error) 959 | case failure(Error) 960 | } 961 | 962 | public extension URLSession { 963 | 964 | /** 965 | Adds a handler that attempts to parse the result of the request into a **Decodable** 966 | 967 | - parameter requestCompletion: The URLSession.dataTask completion 968 | 969 | - returns: The Decoded Result (DResult) 970 | */ 971 | public func decode(requestCompletion: (Data?, Error?)) -> DResult { 972 | switch requestCompletion { 973 | case (.some(let data), .some(let error)): 974 | do { 975 | let decodedData = try JSONDecoder().decode(Value.self, from: data) 976 | return .successWithError(decodedData, error) 977 | } catch let decodeError { 978 | return .failure(decodeError) 979 | } 980 | case (.some(let data), .none): 981 | do { 982 | let decodedData = try JSONDecoder().decode(Value.self, from: data) 983 | return .success(decodedData) 984 | } catch let decodeError { 985 | return .failure(decodeError) 986 | } 987 | case (.none, .some(let error)): 988 | return .failure(error) 989 | 990 | case (.none, .none): 991 | let fallBackError = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Data was not retrieved from request"]) as Error 992 | return .failure(fallBackError) 993 | } 994 | } 995 | 996 | /** 997 | Adds a handler that attempts to parse the result of the request into a **Decodable** 998 | 999 | - parameter completion: A closure that is invoked when the request is finished, containting the desired DataModel to be returned 1000 | 1001 | - returns: The URLSession.dataTask completion 1002 | */ 1003 | public func decode(_ completion: @escaping ((DResult) -> Void)) -> ((Data?, URLResponse?, Error?) -> Void) { 1004 | return { (data, _, error) in 1005 | DispatchQueue.main.async { 1006 | completion(self.decode(requestCompletion: (data, error))) 1007 | } 1008 | } 1009 | } 1010 | } 1011 | ``` 1012 | [See in Codemine](https://github.com/nodes-ios/Codemine/blob/master/Codemine/Extensions/URLSession%2BCodable.swift) 1013 | ## Credits 1014 | Made with ❤️ at [Nodes](http://nodesagency.com). 1015 | 1016 | `Application` and `Then` were borrowed from Hyper's [Sugar](https://github.com/hyperoslo/Sugar) 🙈. 1017 | 1018 | The `DispatchTime` extensions are [Russ Bishop's idea](http://www.russbishop.net/quick-easy-dispatchtime) 🙈. 1019 | 1020 | 1021 | ## License 1022 | **Codemine** is available under the MIT license. See the [LICENSE](https://github.com/nodes-ios/Codemine/blob/master/LICENSE) file for more info. 1023 | -------------------------------------------------------------------------------- /Sources/Application.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Application.swift -------------------------------------------------------------------------------- /Sources/CGPoint+Utilities.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/CGPoint+Utilities.swift -------------------------------------------------------------------------------- /Sources/CGRect+Utilities.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/CGRect+Utilities.swift -------------------------------------------------------------------------------- /Sources/GrandCentralDispatch.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/GrandCentralDispatch.swift -------------------------------------------------------------------------------- /Sources/NSError+Utilities.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/NSError+Utilities.swift -------------------------------------------------------------------------------- /Sources/NSURL+AssetSize.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/NSURL+AssetSize.swift -------------------------------------------------------------------------------- /Sources/NibInstantiable.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Protocols/NibInstantiable.swift -------------------------------------------------------------------------------- /Sources/Operators.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Operators.swift -------------------------------------------------------------------------------- /Sources/String+CaseConverter.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/String+CaseConverter.swift -------------------------------------------------------------------------------- /Sources/String+EmailValidation.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/String+EmailValidation.swift -------------------------------------------------------------------------------- /Sources/String+Range.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/String+Range.swift -------------------------------------------------------------------------------- /Sources/Then.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Then.swift -------------------------------------------------------------------------------- /Sources/UIColor+Hex.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/UIColor+Hex.swift -------------------------------------------------------------------------------- /Sources/UIImage+Utilities.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/UIImage+Utilities.swift -------------------------------------------------------------------------------- /Sources/UIView+Utilities.swift: -------------------------------------------------------------------------------- 1 | ../Codemine/Extensions/UIView+Utilities.swift --------------------------------------------------------------------------------