├── .gitignore ├── .swiftlint.yml ├── .travis.yml ├── Info.plist ├── LICENSE.txt ├── Package.swift ├── README.md ├── SMJobKit.podspec ├── SMJobKit.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── SMJobKit.xccheckout └── xcshareddata │ └── xcschemes │ └── SMJobKit.xcscheme ├── SMJobKit.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── SMJobKit.xccheckout ├── SampleApplication ├── SampleApplication.xcodeproj │ └── project.pbxproj ├── SampleApplication │ ├── AppDelegate.swift │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── SampleApplication-Bridging-Header.h │ ├── SampleApplication-Info.plist │ ├── SampleService.swift │ └── en.lproj │ │ ├── Credits.rtf │ │ └── InfoPlist.strings └── SampleService │ ├── SampleService-Info.plist │ ├── SampleService-Launchd.plist │ └── main.m ├── Sources └── SMJobKit │ ├── BridgingHeader.h │ ├── Client.swift │ ├── ClientUtility.swift │ └── ErrorTypes.swift ├── Tests ├── SMJobKitTests │ ├── ClientTests.swift │ ├── Info.plist │ ├── MissingClient.swift │ └── TestClient.swift └── TestService │ ├── Info.plist │ ├── Launchd.plist │ └── main.m └── Xcode Templates ├── Application └── SMJobKit-Based Application.xctemplate │ ├── README-SMJobKit.md │ ├── TemplateInfo.plist │ └── ___VARIABLE_smjServiceName:RFC1034Identifier___.swift └── Framework & Library └── SMJobKit Service.xctemplate ├── TemplateIcon.icns ├── TemplateInfo.plist ├── ___PACKAGENAMEASIDENTIFIER___-Info.plist ├── ___PACKAGENAMEASIDENTIFIER___-Launchd.plist └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | .build 3 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - line_length 3 | - type_name 4 | force_cast: warning 5 | force_try: warning 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | xcode_workspace: SMJobKit.xcworkspace 3 | xcode_scheme: SMJobKit 4 | osx_image: xcode10.2 5 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSHumanReadableCopyright 26 | Apache License 2.0 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.2 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SMJobKit", 8 | products: [ 9 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 10 | .library( 11 | name: "SMJobKit", 12 | targets: ["SMJobKit"]) 13 | ], 14 | dependencies: [ 15 | // Dependencies declare other packages that this package depends on. 16 | // .package(url: /* package url */, from: "1.0.0"), 17 | ], 18 | targets: [ 19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 20 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 21 | .target( 22 | name: "SMJobKit", 23 | dependencies: []), 24 | .testTarget( 25 | name: "SMJobKitTests", 26 | dependencies: ["SMJobKit"]) 27 | ], 28 | swiftLanguageVersions: [.v4, .v4_2, .version("5")] 29 | ) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SMJobKit 2 | ======== 3 | 4 | Using SMJobBless and friends is rather… painful. SMJobKit does everything in its power to 5 | alleviate that and get you back to writing awesome macOS apps. 6 | 7 | SMJobKit is more than just a framework/library to link against. It gives you: 8 | 9 | * A Xcode target template for SMJobBless-ready launchd services, completely configured for proper 10 | code signing! 11 | 12 | * A client abstraction that manages installing/upgrading your app's service(s). 13 | 14 | * A service library that pulls in as little additional code as possible. Less surface area for 15 | security vulnerabilities! 16 | 17 | 18 | Project Configuration 19 | --------------------- 20 | 21 | To get started, pull the SMJobKit project into your own project or workspace. Have your application 22 | depend on the SMJobKit framework, and hit build. In addition to building the framework, this also 23 | causes the Xcode template to install its self into `~/Library/Developer/Xcode/Templates`. 24 | 25 | Next, you should set up your service helper/target: Add a new _SMJobKit Service_ target to the 26 | project. This is relatively configuration-heavy, so you should probably build it right away to make 27 | sure everything is properly configured (and your code signing certificates are in order). You may 28 | want to review the [template's documentation](https://github.com/IngmarStein/SMJobKit/tree/master/Xcode%20Templates/Framework%20%26%20Library/SMJobKit%20Service.xctemplate) 29 | for an in-depth explanation of what it is doing for you. 30 | 31 | Finally, you need to add a Copy Files build phase to your application target. The destination 32 | should be "Wrapper" with a subpath of `Contents/Library/LaunchServices`. Add the service's built 33 | product to the list. Make sure you add a dependency on your service target! 34 | 35 | And, hopefully, that's all you need to do in order to configure your project! 36 | 37 | 38 | Client Abstraction 39 | ------------------ 40 | 41 | You'll want to create a subclass of `Client` in your application, and override 42 | `serviceIdentifier` at the very least. 43 | -------------------------------------------------------------------------------- /SMJobKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "SMJobKit" 3 | s.version = "0.0.21" 4 | s.swift_version = '5.0' 5 | s.summary = "Framework that simplifies SMJobBless." 6 | s.homepage = "https://github.com/IngmarStein/SMJobKit" 7 | s.authors = { "Ian MacLeod" => "ian@nevir.net", "Ingmar Stein" => "IngmarStein@gmail.com" } 8 | s.source = { :git => "https://github.com/IngmarStein/SMJobKit.git", :tag => "0.0.19" } 9 | s.platform = :osx, '10.9' 10 | s.source_files = 'Sources/**/*.{h,swift}' 11 | s.framework = 'ServiceManagement', 'Security' 12 | s.requires_arc = true 13 | s.static_framework = true 14 | s.public_header_files = 'Sources/*.h' 15 | s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE.txt" } 16 | s.description = <<-DESC 17 | Using SMJobBless and friends is rather ...painful. SMJobKit does everything in its power to alleviate that and get you back to writing awesome macOS apps. 18 | 19 | SMJobKit is more than just a framework/library to link against. It gives you: 20 | - A Xcode target template for SMJobBless-ready launchd services, completely configured for proper code signing! 21 | - A client abstraction that manages installing/upgrading your app's service(s). 22 | - A service library that pulls in as little additional code as possible. Less surface area for security vulnerabilities! 23 | DESC 24 | end 25 | -------------------------------------------------------------------------------- /SMJobKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | 3CCC06D015AA823000C84BE1 /* Xcode Templates */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = 3CCC06D115AA823000C84BE1 /* Build configuration list for PBXAggregateTarget "Xcode Templates" */; 13 | buildPhases = ( 14 | 3CD9BC9715B24DBF00F0007B /* Copy Templates */, 15 | ); 16 | dependencies = ( 17 | ); 18 | name = "Xcode Templates"; 19 | productName = "SMJobKit Service Template"; 20 | }; 21 | /* End PBXAggregateTarget section */ 22 | 23 | /* Begin PBXBuildFile section */ 24 | 3C2BFAB515AB33020011FA52 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C2BFAB415AB33020011FA52 /* main.m */; }; 25 | 3C2BFABE15AB33EF0011FA52 /* net.nevir.SMJobKitTests.TestService in Copy Services */ = {isa = PBXBuildFile; fileRef = 3C2BFAB015AB33020011FA52 /* net.nevir.SMJobKitTests.TestService */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 26 | 3CA1508F15A91179001CF9F8 /* SMJobKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CA1507115A91179001CF9F8 /* SMJobKit.framework */; }; 27 | 95340BA21AC83DB400DE4879 /* ErrorTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95340BA11AC83DB400DE4879 /* ErrorTypes.swift */; }; 28 | 95340BA41AC84C9C00DE4879 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95340BA31AC84C9C00DE4879 /* Client.swift */; }; 29 | 95340BA61AC8555D00DE4879 /* MissingClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95340BA51AC8555D00DE4879 /* MissingClient.swift */; }; 30 | 95340BA81AC855A100DE4879 /* TestClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95340BA71AC855A100DE4879 /* TestClient.swift */; }; 31 | 95340BAA1AC855DE00DE4879 /* ClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95340BA91AC855DE00DE4879 /* ClientTests.swift */; }; 32 | 956253011AC837A900D93E91 /* ClientUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956253001AC837A900D93E91 /* ClientUtility.swift */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXContainerItemProxy section */ 36 | 3C2BFABF15AB34070011FA52 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 3CA1506715A91179001CF9F8 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 3C2BFAAF15AB33020011FA52; 41 | remoteInfo = TestService; 42 | }; 43 | 3CA1508D15A91179001CF9F8 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 3CA1506715A91179001CF9F8 /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = 3CA1507015A91179001CF9F8; 48 | remoteInfo = SMJobKit; 49 | }; 50 | /* End PBXContainerItemProxy section */ 51 | 52 | /* Begin PBXCopyFilesBuildPhase section */ 53 | 3C2BFABD15AB33CB0011FA52 /* Copy Services */ = { 54 | isa = PBXCopyFilesBuildPhase; 55 | buildActionMask = 2147483647; 56 | dstPath = Contents/Library/LaunchServices; 57 | dstSubfolderSpec = 1; 58 | files = ( 59 | 3C2BFABE15AB33EF0011FA52 /* net.nevir.SMJobKitTests.TestService in Copy Services */, 60 | ); 61 | name = "Copy Services"; 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXCopyFilesBuildPhase section */ 65 | 66 | /* Begin PBXFileReference section */ 67 | 3C2BFAB015AB33020011FA52 /* net.nevir.SMJobKitTests.TestService */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = net.nevir.SMJobKitTests.TestService; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | 3C2BFAB415AB33020011FA52 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 69 | 3C2BFAB615AB33020011FA52 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 70 | 3C2BFAB715AB33020011FA52 /* Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Launchd.plist; sourceTree = ""; }; 71 | 3C560DAD15A9460E00A05BC2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | 3CA1507115A91179001CF9F8 /* SMJobKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SMJobKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | 3CA1507C15A91179001CF9F8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Info.plist; sourceTree = ""; }; 74 | 3CA1508915A91179001CF9F8 /* SMJobKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SMJobKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 3CA150A115A911A0001CF9F8 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 76 | 3CA150A215A911A7001CF9F8 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 77 | 3CCC06D515AA837E00C84BE1 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 78 | 3CCC06D615AA837E00C84BE1 /* TemplateIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = TemplateIcon.icns; sourceTree = ""; }; 79 | 3CCC06D715AA837E00C84BE1 /* TemplateInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TemplateInfo.plist; sourceTree = ""; }; 80 | 3CD9BC9815B2503F00F0007B /* ___PACKAGENAMEASIDENTIFIER___-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "___PACKAGENAMEASIDENTIFIER___-Info.plist"; sourceTree = ""; }; 81 | 3CD9BC9915B2503F00F0007B /* ___PACKAGENAMEASIDENTIFIER___-Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "___PACKAGENAMEASIDENTIFIER___-Launchd.plist"; sourceTree = ""; }; 82 | 3CD9BCD315B2632D00F0007B /* TemplateInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = TemplateInfo.plist; sourceTree = ""; }; 83 | 3CFB0E2015B37DE400FA0E6B /* README-SMJobKit.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = "README-SMJobKit.md"; sourceTree = ""; }; 84 | 95340BA11AC83DB400DE4879 /* ErrorTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ErrorTypes.swift; path = SMJobKit/ErrorTypes.swift; sourceTree = ""; }; 85 | 95340BA31AC84C9C00DE4879 /* Client.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Client.swift; path = SMJobKit/Client.swift; sourceTree = ""; }; 86 | 95340BA51AC8555D00DE4879 /* MissingClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MissingClient.swift; sourceTree = ""; }; 87 | 95340BA71AC855A100DE4879 /* TestClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestClient.swift; sourceTree = ""; }; 88 | 95340BA91AC855DE00DE4879 /* ClientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClientTests.swift; sourceTree = ""; }; 89 | 956253001AC837A900D93E91 /* ClientUtility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ClientUtility.swift; path = SMJobKit/ClientUtility.swift; sourceTree = ""; }; 90 | 958CB2A81AC95B6300D4FE65 /* ___VARIABLE_smjServiceName:RFC1034Identifier___.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "___VARIABLE_smjServiceName:RFC1034Identifier___.swift"; sourceTree = ""; }; 91 | 95CA05321B934371000ABDCE /* BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BridgingHeader.h; path = SMJobKit/BridgingHeader.h; sourceTree = ""; }; 92 | /* End PBXFileReference section */ 93 | 94 | /* Begin PBXFrameworksBuildPhase section */ 95 | 3C2BFAAE15AB33020011FA52 /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | 3CA1506D15A91179001CF9F8 /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | 3CA1508515A91179001CF9F8 /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | 3CA1508F15A91179001CF9F8 /* SMJobKit.framework in Frameworks */, 114 | ); 115 | runOnlyForDeploymentPostprocessing = 0; 116 | }; 117 | /* End PBXFrameworksBuildPhase section */ 118 | 119 | /* Begin PBXGroup section */ 120 | 3C2BFA8815AB2E570011FA52 /* Supporting Files */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 95CA05321B934371000ABDCE /* BridgingHeader.h */, 124 | 3CA1507C15A91179001CF9F8 /* Info.plist */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | 3C2BFA8915AB2E870011FA52 /* Public */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 95340BA31AC84C9C00DE4879 /* Client.swift */, 133 | 95340BA11AC83DB400DE4879 /* ErrorTypes.swift */, 134 | ); 135 | name = Public; 136 | path = ..; 137 | sourceTree = ""; 138 | }; 139 | 3C2BFA8A15AB2E8F0011FA52 /* Private */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 956253001AC837A900D93E91 /* ClientUtility.swift */, 143 | ); 144 | name = Private; 145 | path = ..; 146 | sourceTree = ""; 147 | }; 148 | 3C2BFAA815AB30EB0011FA52 /* Supporting Files */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 3C560DAD15A9460E00A05BC2 /* Info.plist */, 152 | ); 153 | name = "Supporting Files"; 154 | sourceTree = ""; 155 | }; 156 | 3C2BFAA915AB31240011FA52 /* Fixtures */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 95340BA51AC8555D00DE4879 /* MissingClient.swift */, 160 | 95340BA71AC855A100DE4879 /* TestClient.swift */, 161 | ); 162 | name = Fixtures; 163 | sourceTree = ""; 164 | }; 165 | 3C2BFAB315AB33020011FA52 /* TestService */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 3C2BFAB415AB33020011FA52 /* main.m */, 169 | 3C2BFAB615AB33020011FA52 /* Info.plist */, 170 | 3C2BFAB715AB33020011FA52 /* Launchd.plist */, 171 | ); 172 | path = TestService; 173 | sourceTree = ""; 174 | }; 175 | 3C560DAB15A9460E00A05BC2 /* Tests */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 3C560DAC15A9460E00A05BC2 /* SMJobKitTests */, 179 | 3C2BFAB315AB33020011FA52 /* TestService */, 180 | ); 181 | path = Tests; 182 | sourceTree = ""; 183 | }; 184 | 3C560DAC15A9460E00A05BC2 /* SMJobKitTests */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 95340BA91AC855DE00DE4879 /* ClientTests.swift */, 188 | 3C2BFAA915AB31240011FA52 /* Fixtures */, 189 | 3C2BFAA815AB30EB0011FA52 /* Supporting Files */, 190 | ); 191 | path = SMJobKitTests; 192 | sourceTree = ""; 193 | }; 194 | 3CA1506515A91179001CF9F8 = { 195 | isa = PBXGroup; 196 | children = ( 197 | 3CA150A115A911A0001CF9F8 /* README.md */, 198 | 3CA150A215A911A7001CF9F8 /* LICENSE.txt */, 199 | 3CA1507A15A91179001CF9F8 /* Sources */, 200 | 3C560DAB15A9460E00A05BC2 /* Tests */, 201 | 3CCC07AA15AA949400C84BE1 /* Xcode Templates */, 202 | 3CA1507215A91179001CF9F8 /* Products */, 203 | ); 204 | sourceTree = ""; 205 | }; 206 | 3CA1507215A91179001CF9F8 /* Products */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | 3CA1507115A91179001CF9F8 /* SMJobKit.framework */, 210 | 3CA1508915A91179001CF9F8 /* SMJobKitTests.xctest */, 211 | 3C2BFAB015AB33020011FA52 /* net.nevir.SMJobKitTests.TestService */, 212 | ); 213 | name = Products; 214 | sourceTree = ""; 215 | }; 216 | 3CA1507A15A91179001CF9F8 /* Sources */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | 9568253422B447610027EB49 /* SMJobKit */, 220 | 3C2BFA8815AB2E570011FA52 /* Supporting Files */, 221 | ); 222 | path = Sources; 223 | sourceTree = ""; 224 | }; 225 | 3CCC06C515AA810D00C84BE1 /* SMJobKit Service.xctemplate */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | 3CD9BC9815B2503F00F0007B /* ___PACKAGENAMEASIDENTIFIER___-Info.plist */, 229 | 3CD9BC9915B2503F00F0007B /* ___PACKAGENAMEASIDENTIFIER___-Launchd.plist */, 230 | 3CCC06D515AA837E00C84BE1 /* main.m */, 231 | 3CCC06D615AA837E00C84BE1 /* TemplateIcon.icns */, 232 | 3CCC06D715AA837E00C84BE1 /* TemplateInfo.plist */, 233 | ); 234 | path = "SMJobKit Service.xctemplate"; 235 | sourceTree = ""; 236 | }; 237 | 3CCC07AA15AA949400C84BE1 /* Xcode Templates */ = { 238 | isa = PBXGroup; 239 | children = ( 240 | 3CD9BCCF15B2632D00F0007B /* Application */, 241 | 3CD9BC9615B24C2900F0007B /* Framework & Library */, 242 | ); 243 | path = "Xcode Templates"; 244 | sourceTree = ""; 245 | }; 246 | 3CD9BC9615B24C2900F0007B /* Framework & Library */ = { 247 | isa = PBXGroup; 248 | children = ( 249 | 3CCC06C515AA810D00C84BE1 /* SMJobKit Service.xctemplate */, 250 | ); 251 | path = "Framework & Library"; 252 | sourceTree = ""; 253 | }; 254 | 3CD9BCCF15B2632D00F0007B /* Application */ = { 255 | isa = PBXGroup; 256 | children = ( 257 | 3CD9BCD015B2632D00F0007B /* SMJobKit-Based Application.xctemplate */, 258 | ); 259 | path = Application; 260 | sourceTree = ""; 261 | }; 262 | 3CD9BCD015B2632D00F0007B /* SMJobKit-Based Application.xctemplate */ = { 263 | isa = PBXGroup; 264 | children = ( 265 | 958CB2A81AC95B6300D4FE65 /* ___VARIABLE_smjServiceName:RFC1034Identifier___.swift */, 266 | 3CFB0E2015B37DE400FA0E6B /* README-SMJobKit.md */, 267 | 3CD9BCD315B2632D00F0007B /* TemplateInfo.plist */, 268 | ); 269 | path = "SMJobKit-Based Application.xctemplate"; 270 | sourceTree = ""; 271 | }; 272 | 9568253422B447610027EB49 /* SMJobKit */ = { 273 | isa = PBXGroup; 274 | children = ( 275 | 3C2BFA8915AB2E870011FA52 /* Public */, 276 | 3C2BFA8A15AB2E8F0011FA52 /* Private */, 277 | ); 278 | path = SMJobKit; 279 | sourceTree = ""; 280 | }; 281 | /* End PBXGroup section */ 282 | 283 | /* Begin PBXHeadersBuildPhase section */ 284 | 3CA1506E15A91179001CF9F8 /* Headers */ = { 285 | isa = PBXHeadersBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | }; 291 | /* End PBXHeadersBuildPhase section */ 292 | 293 | /* Begin PBXNativeTarget section */ 294 | 3C2BFAAF15AB33020011FA52 /* TestService */ = { 295 | isa = PBXNativeTarget; 296 | buildConfigurationList = 3C2BFAB815AB33020011FA52 /* Build configuration list for PBXNativeTarget "TestService" */; 297 | buildPhases = ( 298 | 3C4C2B0C15ABF89300775A8B /* Preprocess Files */, 299 | 3C2BFAAD15AB33020011FA52 /* Sources */, 300 | 3C2BFAAE15AB33020011FA52 /* Frameworks */, 301 | ); 302 | buildRules = ( 303 | ); 304 | dependencies = ( 305 | ); 306 | name = TestService; 307 | productName = TestService; 308 | productReference = 3C2BFAB015AB33020011FA52 /* net.nevir.SMJobKitTests.TestService */; 309 | productType = "com.apple.product-type.tool"; 310 | }; 311 | 3CA1507015A91179001CF9F8 /* SMJobKit */ = { 312 | isa = PBXNativeTarget; 313 | buildConfigurationList = 3CA1509B15A91179001CF9F8 /* Build configuration list for PBXNativeTarget "SMJobKit" */; 314 | buildPhases = ( 315 | 3CA1506C15A91179001CF9F8 /* Sources */, 316 | 3CA1506D15A91179001CF9F8 /* Frameworks */, 317 | 3CA1506E15A91179001CF9F8 /* Headers */, 318 | 3CA1506F15A91179001CF9F8 /* Resources */, 319 | ); 320 | buildRules = ( 321 | ); 322 | dependencies = ( 323 | ); 324 | name = SMJobKit; 325 | productName = SMJobKit; 326 | productReference = 3CA1507115A91179001CF9F8 /* SMJobKit.framework */; 327 | productType = "com.apple.product-type.framework"; 328 | }; 329 | 3CA1508815A91179001CF9F8 /* SMJobKitTests */ = { 330 | isa = PBXNativeTarget; 331 | buildConfigurationList = 3CA1509E15A91179001CF9F8 /* Build configuration list for PBXNativeTarget "SMJobKitTests" */; 332 | buildPhases = ( 333 | 3CA1508415A91179001CF9F8 /* Sources */, 334 | 3CA1508515A91179001CF9F8 /* Frameworks */, 335 | 3C2BFABD15AB33CB0011FA52 /* Copy Services */, 336 | ); 337 | buildRules = ( 338 | ); 339 | dependencies = ( 340 | 3CA1508E15A91179001CF9F8 /* PBXTargetDependency */, 341 | 3C2BFAC015AB34070011FA52 /* PBXTargetDependency */, 342 | ); 343 | name = SMJobKitTests; 344 | productName = SMJobKitTests; 345 | productReference = 3CA1508915A91179001CF9F8 /* SMJobKitTests.xctest */; 346 | productType = "com.apple.product-type.bundle.unit-test"; 347 | }; 348 | /* End PBXNativeTarget section */ 349 | 350 | /* Begin PBXProject section */ 351 | 3CA1506715A91179001CF9F8 /* Project object */ = { 352 | isa = PBXProject; 353 | attributes = { 354 | CLASSPREFIX = SMJ; 355 | LastSwiftUpdateCheck = 0700; 356 | LastTestingUpgradeCheck = 0630; 357 | LastUpgradeCheck = 1100; 358 | TargetAttributes = { 359 | 3C2BFAAF15AB33020011FA52 = { 360 | ProvisioningStyle = Manual; 361 | }; 362 | 3CA1507015A91179001CF9F8 = { 363 | LastSwiftMigration = 1020; 364 | }; 365 | }; 366 | }; 367 | buildConfigurationList = 3CA1506A15A91179001CF9F8 /* Build configuration list for PBXProject "SMJobKit" */; 368 | compatibilityVersion = "Xcode 10.0"; 369 | developmentRegion = en; 370 | hasScannedForEncodings = 0; 371 | knownRegions = ( 372 | en, 373 | Base, 374 | ); 375 | mainGroup = 3CA1506515A91179001CF9F8; 376 | productRefGroup = 3CA1507215A91179001CF9F8 /* Products */; 377 | projectDirPath = ""; 378 | projectRoot = ""; 379 | targets = ( 380 | 3CA1507015A91179001CF9F8 /* SMJobKit */, 381 | 3CA1508815A91179001CF9F8 /* SMJobKitTests */, 382 | 3C2BFAAF15AB33020011FA52 /* TestService */, 383 | 3CCC06D015AA823000C84BE1 /* Xcode Templates */, 384 | ); 385 | }; 386 | /* End PBXProject section */ 387 | 388 | /* Begin PBXResourcesBuildPhase section */ 389 | 3CA1506F15A91179001CF9F8 /* Resources */ = { 390 | isa = PBXResourcesBuildPhase; 391 | buildActionMask = 2147483647; 392 | files = ( 393 | ); 394 | runOnlyForDeploymentPostprocessing = 0; 395 | }; 396 | /* End PBXResourcesBuildPhase section */ 397 | 398 | /* Begin PBXShellScriptBuildPhase section */ 399 | 3C4C2B0C15ABF89300775A8B /* Preprocess Files */ = { 400 | isa = PBXShellScriptBuildPhase; 401 | buildActionMask = 2147483647; 402 | files = ( 403 | ); 404 | inputPaths = ( 405 | ); 406 | name = "Preprocess Files"; 407 | outputPaths = ( 408 | ); 409 | runOnlyForDeploymentPostprocessing = 0; 410 | shellPath = "/usr/bin/env ruby"; 411 | shellScript = "# Generic preprocessing for ${ENV_VAR} with output to the build dir.\n\nrequire 'cgi'\nrequire 'fileutils'\n\nmissing_keys = ['BUILD_DIR', 'CODE_SIGN_IDENTITY', 'SMJ_PREPROCESS_FILES', 'SMJ_PREPROCESS_DIR'] - ENV.keys\nraise \"Missing required ENV values: #{missing_keys.inspect}\" if missing_keys.size > 0\n\n# SMJ_PREPROCESS_FILES is a comma-separated list of *relative* file paths to preprocess\n# and spit out into the SMJ_PREPROCESS_DIR (w/ the same relative paths as given)\nfiles_to_preprocess = ENV['SMJ_PREPROCESS_FILES'].split(',').map(&:strip)\n\n\n# Environment Cleanup\n# -------------------\ndummy_path = \"#{ENV['BUILD_DIR']}/SMJobKitCodeSigningDummy\"\n\nidentity = ENV['CODE_SIGN_IDENTITY']\n# If you use the generic code signing identity, chances are that it'll conflict.\nidentity = \"#{identity}:\" if identity.end_with? ' Developer'\n\n# We can't seem to get direct access to the code signing certificate that Xcode has\n# selected at this point :(\n`touch #{dummy_path}`\n`codesign --force --sign \"#{identity}\" \"#{dummy_path}\"`\nresult = `codesign --display --verbose --verbose \"#{dummy_path}\" 2>&1`\n`rm #{dummy_path}`\n\nENV['CODE_SIGN_IDENTITY'] = result[/Authority\\=(.*#{Regexp.escape(identity)}.*)/, 1]\n\n\n# Actual Preprocessing\n# --------------------\n\nfiles_to_preprocess.each do |path|\n target_path = File.join(ENV['SMJ_PREPROCESS_DIR'], path)\n FileUtils.mkpath File.dirname(target_path)\n\n open(path) do |input|\n open(target_path, 'w') do |output|\n # Specify macros via ${VAR_NAME} in the preprocessed file. Same as regular\n # Info.plist preprocessing.\n output.write input.read.gsub(/\\$\\{([A-Z_]+)\\}/) { CGI.escapeHTML(ENV[$1]) }\n end\n puts target_path\n end\nend\n"; 412 | }; 413 | 3CD9BC9715B24DBF00F0007B /* Copy Templates */ = { 414 | isa = PBXShellScriptBuildPhase; 415 | buildActionMask = 2147483647; 416 | files = ( 417 | ); 418 | inputPaths = ( 419 | ); 420 | name = "Copy Templates"; 421 | outputPaths = ( 422 | ); 423 | runOnlyForDeploymentPostprocessing = 0; 424 | shellPath = "/usr/bin/env ruby"; 425 | shellScript = "source_dir = \"Xcode Templates\"\ndest_dir = File.expand_path(\"~/Library/Developer/Xcode/Templates\")\n\nDir[\"#{source_dir}/*/*\"].each do |template|\n base_path = template[/([^\\/]+\\/[^\\/]+)$/, 1]\n target_path = File.join(dest_dir, base_path)\n\n `rm -rf \"#{target_path}\"`\n `mkdir -p \"#{File.dirname(target_path)}\"`\n `cp -R \"#{source_dir}/#{base_path}\" \"#{target_path}\"`\n\n puts \"Copied #{base_path}\"\nend\n"; 426 | }; 427 | /* End PBXShellScriptBuildPhase section */ 428 | 429 | /* Begin PBXSourcesBuildPhase section */ 430 | 3C2BFAAD15AB33020011FA52 /* Sources */ = { 431 | isa = PBXSourcesBuildPhase; 432 | buildActionMask = 2147483647; 433 | files = ( 434 | 3C2BFAB515AB33020011FA52 /* main.m in Sources */, 435 | ); 436 | runOnlyForDeploymentPostprocessing = 0; 437 | }; 438 | 3CA1506C15A91179001CF9F8 /* Sources */ = { 439 | isa = PBXSourcesBuildPhase; 440 | buildActionMask = 2147483647; 441 | files = ( 442 | 95340BA41AC84C9C00DE4879 /* Client.swift in Sources */, 443 | 95340BA21AC83DB400DE4879 /* ErrorTypes.swift in Sources */, 444 | 956253011AC837A900D93E91 /* ClientUtility.swift in Sources */, 445 | ); 446 | runOnlyForDeploymentPostprocessing = 0; 447 | }; 448 | 3CA1508415A91179001CF9F8 /* Sources */ = { 449 | isa = PBXSourcesBuildPhase; 450 | buildActionMask = 2147483647; 451 | files = ( 452 | 95340BA61AC8555D00DE4879 /* MissingClient.swift in Sources */, 453 | 95340BA81AC855A100DE4879 /* TestClient.swift in Sources */, 454 | 95340BAA1AC855DE00DE4879 /* ClientTests.swift in Sources */, 455 | ); 456 | runOnlyForDeploymentPostprocessing = 0; 457 | }; 458 | /* End PBXSourcesBuildPhase section */ 459 | 460 | /* Begin PBXTargetDependency section */ 461 | 3C2BFAC015AB34070011FA52 /* PBXTargetDependency */ = { 462 | isa = PBXTargetDependency; 463 | target = 3C2BFAAF15AB33020011FA52 /* TestService */; 464 | targetProxy = 3C2BFABF15AB34070011FA52 /* PBXContainerItemProxy */; 465 | }; 466 | 3CA1508E15A91179001CF9F8 /* PBXTargetDependency */ = { 467 | isa = PBXTargetDependency; 468 | target = 3CA1507015A91179001CF9F8 /* SMJobKit */; 469 | targetProxy = 3CA1508D15A91179001CF9F8 /* PBXContainerItemProxy */; 470 | }; 471 | /* End PBXTargetDependency section */ 472 | 473 | /* Begin XCBuildConfiguration section */ 474 | 3C2BFAB915AB33020011FA52 /* Debug */ = { 475 | isa = XCBuildConfiguration; 476 | buildSettings = { 477 | CLANG_ENABLE_OBJC_WEAK = YES; 478 | CODE_SIGN_IDENTITY = "Developer ID Application"; 479 | CODE_SIGN_STYLE = Manual; 480 | DEVELOPMENT_TEAM = ADVP2P7SJK; 481 | ENABLE_HARDENED_RUNTIME = YES; 482 | OTHER_LDFLAGS = ( 483 | "-sectcreate", 484 | __TEXT, 485 | __info_plist, 486 | "\"$(SMJ_PREPROCESS_DIR)/Tests/TestService/Info.plist\"", 487 | "-sectcreate", 488 | __TEXT, 489 | __launchd_plist, 490 | "\"$(SMJ_PREPROCESS_DIR)/Tests/TestService/Launchd.plist\"", 491 | ); 492 | PRODUCT_NAME = "net.nevir.SMJobKitTests.$(TARGET_NAME)"; 493 | PROVISIONING_PROFILE_SPECIFIER = ""; 494 | SKIP_INSTALL = YES; 495 | SMJ_PREPROCESS_DIR = "$(BUILD_DIR)/Preprocessed"; 496 | SMJ_PREPROCESS_FILES = "Tests/TestService/Info.plist, Tests/TestService/Launchd.plist"; 497 | }; 498 | name = Debug; 499 | }; 500 | 3C2BFABA15AB33020011FA52 /* Release */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | CLANG_ENABLE_OBJC_WEAK = YES; 504 | CODE_SIGN_IDENTITY = "Developer ID Application"; 505 | CODE_SIGN_STYLE = Manual; 506 | DEVELOPMENT_TEAM = ADVP2P7SJK; 507 | ENABLE_HARDENED_RUNTIME = YES; 508 | OTHER_LDFLAGS = ( 509 | "-sectcreate", 510 | __TEXT, 511 | __info_plist, 512 | "\"$(SMJ_PREPROCESS_DIR)/Tests/TestService/Info.plist\"", 513 | "-sectcreate", 514 | __TEXT, 515 | __launchd_plist, 516 | "\"$(SMJ_PREPROCESS_DIR)/Tests/TestService/Launchd.plist\"", 517 | ); 518 | PRODUCT_NAME = "net.nevir.SMJobKitTests.$(TARGET_NAME)"; 519 | PROVISIONING_PROFILE_SPECIFIER = ""; 520 | SKIP_INSTALL = YES; 521 | SMJ_PREPROCESS_DIR = "$(BUILD_DIR)/Preprocessed"; 522 | SMJ_PREPROCESS_FILES = "Tests/TestService/Info.plist, Tests/TestService/Launchd.plist"; 523 | }; 524 | name = Release; 525 | }; 526 | 3CA1509915A91179001CF9F8 /* Debug */ = { 527 | isa = XCBuildConfiguration; 528 | buildSettings = { 529 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 530 | CLANG_ENABLE_MODULES = YES; 531 | CLANG_WARN_ASSIGN_ENUM = YES; 532 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 533 | CLANG_WARN_BOOL_CONVERSION = YES; 534 | CLANG_WARN_COMMA = YES; 535 | CLANG_WARN_CONSTANT_CONVERSION = YES; 536 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 537 | CLANG_WARN_EMPTY_BODY = YES; 538 | CLANG_WARN_ENUM_CONVERSION = YES; 539 | CLANG_WARN_INFINITE_RECURSION = YES; 540 | CLANG_WARN_INT_CONVERSION = YES; 541 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 542 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 543 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 544 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 545 | CLANG_WARN_STRICT_PROTOTYPES = YES; 546 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 547 | CLANG_WARN_UNREACHABLE_CODE = YES; 548 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 549 | COMBINE_HIDPI_IMAGES = YES; 550 | ENABLE_NS_ASSERTIONS = NO; 551 | ENABLE_STRICT_OBJC_MSGSEND = YES; 552 | ENABLE_TESTABILITY = YES; 553 | GCC_NO_COMMON_BLOCKS = YES; 554 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 555 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 556 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 557 | GCC_WARN_PEDANTIC = YES; 558 | GCC_WARN_UNDECLARED_SELECTOR = YES; 559 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 560 | GCC_WARN_UNUSED_FUNCTION = YES; 561 | GCC_WARN_UNUSED_VARIABLE = YES; 562 | MACOSX_DEPLOYMENT_TARGET = 10.9; 563 | ONLY_ACTIVE_ARCH = YES; 564 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 565 | SWIFT_VERSION = 5.0; 566 | }; 567 | name = Debug; 568 | }; 569 | 3CA1509A15A91179001CF9F8 /* Release */ = { 570 | isa = XCBuildConfiguration; 571 | buildSettings = { 572 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 573 | CLANG_ENABLE_MODULES = YES; 574 | CLANG_WARN_ASSIGN_ENUM = YES; 575 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 576 | CLANG_WARN_BOOL_CONVERSION = YES; 577 | CLANG_WARN_COMMA = YES; 578 | CLANG_WARN_CONSTANT_CONVERSION = YES; 579 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 580 | CLANG_WARN_EMPTY_BODY = YES; 581 | CLANG_WARN_ENUM_CONVERSION = YES; 582 | CLANG_WARN_INFINITE_RECURSION = YES; 583 | CLANG_WARN_INT_CONVERSION = YES; 584 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 585 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 586 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 587 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 588 | CLANG_WARN_STRICT_PROTOTYPES = YES; 589 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 590 | CLANG_WARN_UNREACHABLE_CODE = YES; 591 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 592 | COMBINE_HIDPI_IMAGES = YES; 593 | ENABLE_STRICT_OBJC_MSGSEND = YES; 594 | GCC_NO_COMMON_BLOCKS = YES; 595 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 596 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 597 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 598 | GCC_WARN_PEDANTIC = YES; 599 | GCC_WARN_UNDECLARED_SELECTOR = YES; 600 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 601 | GCC_WARN_UNUSED_FUNCTION = YES; 602 | GCC_WARN_UNUSED_VARIABLE = YES; 603 | MACOSX_DEPLOYMENT_TARGET = 10.9; 604 | SWIFT_COMPILATION_MODE = wholemodule; 605 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 606 | SWIFT_VERSION = 5.0; 607 | }; 608 | name = Release; 609 | }; 610 | 3CA1509C15A91179001CF9F8 /* Debug */ = { 611 | isa = XCBuildConfiguration; 612 | buildSettings = { 613 | CLANG_ENABLE_MODULES = YES; 614 | CLANG_ENABLE_OBJC_WEAK = YES; 615 | DEFINES_MODULE = YES; 616 | DYLIB_COMPATIBILITY_VERSION = 1; 617 | DYLIB_CURRENT_VERSION = 1; 618 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 619 | INFOPLIST_FILE = Info.plist; 620 | LD_RUNPATH_SEARCH_PATHS = ( 621 | "$(inherited)", 622 | "@executable_path/../Frameworks", 623 | "@loader_path/Frameworks", 624 | ); 625 | PRODUCT_BUNDLE_IDENTIFIER = "net.nevir.${PRODUCT_NAME:rfc1034identifier}"; 626 | PRODUCT_NAME = SMJobKit; 627 | SKIP_INSTALL = YES; 628 | SWIFT_OBJC_BRIDGING_HEADER = Sources/SMJobKit/BridgingHeader.h; 629 | }; 630 | name = Debug; 631 | }; 632 | 3CA1509D15A91179001CF9F8 /* Release */ = { 633 | isa = XCBuildConfiguration; 634 | buildSettings = { 635 | CLANG_ENABLE_MODULES = YES; 636 | CLANG_ENABLE_OBJC_WEAK = YES; 637 | DEFINES_MODULE = YES; 638 | DYLIB_COMPATIBILITY_VERSION = 1; 639 | DYLIB_CURRENT_VERSION = 1; 640 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 641 | INFOPLIST_FILE = Info.plist; 642 | LD_RUNPATH_SEARCH_PATHS = ( 643 | "$(inherited)", 644 | "@executable_path/../Frameworks", 645 | "@loader_path/Frameworks", 646 | ); 647 | PRODUCT_BUNDLE_IDENTIFIER = "net.nevir.${PRODUCT_NAME:rfc1034identifier}"; 648 | PRODUCT_NAME = SMJobKit; 649 | SKIP_INSTALL = YES; 650 | SWIFT_OBJC_BRIDGING_HEADER = Sources/SMJobKit/BridgingHeader.h; 651 | }; 652 | name = Release; 653 | }; 654 | 3CA1509F15A91179001CF9F8 /* Debug */ = { 655 | isa = XCBuildConfiguration; 656 | buildSettings = { 657 | CLANG_ENABLE_OBJC_WEAK = YES; 658 | COPY_PHASE_STRIP = NO; 659 | FRAMEWORK_SEARCH_PATHS = ( 660 | "$(DEVELOPER_FRAMEWORKS_DIR)", 661 | "$(inherited)", 662 | ); 663 | GCC_PREPROCESSOR_DEFINITIONS = ( 664 | "DEBUG=1", 665 | "$(inherited)", 666 | ); 667 | INFOPLIST_FILE = Tests/SMJobKitTests/Info.plist; 668 | LD_RUNPATH_SEARCH_PATHS = ( 669 | "$(inherited)", 670 | "@executable_path/../Frameworks", 671 | "@loader_path/../Frameworks", 672 | ); 673 | PRODUCT_BUNDLE_IDENTIFIER = "net.nevir.${PRODUCT_NAME:rfc1034identifier}"; 674 | PRODUCT_NAME = SMJobKitTests; 675 | }; 676 | name = Debug; 677 | }; 678 | 3CA150A015A91179001CF9F8 /* Release */ = { 679 | isa = XCBuildConfiguration; 680 | buildSettings = { 681 | CLANG_ENABLE_OBJC_WEAK = YES; 682 | COPY_PHASE_STRIP = NO; 683 | FRAMEWORK_SEARCH_PATHS = ( 684 | "$(DEVELOPER_FRAMEWORKS_DIR)", 685 | "$(inherited)", 686 | ); 687 | INFOPLIST_FILE = Tests/SMJobKitTests/Info.plist; 688 | LD_RUNPATH_SEARCH_PATHS = ( 689 | "$(inherited)", 690 | "@executable_path/../Frameworks", 691 | "@loader_path/../Frameworks", 692 | ); 693 | PRODUCT_BUNDLE_IDENTIFIER = "net.nevir.${PRODUCT_NAME:rfc1034identifier}"; 694 | PRODUCT_NAME = SMJobKitTests; 695 | }; 696 | name = Release; 697 | }; 698 | 3CCC06D215AA823000C84BE1 /* Debug */ = { 699 | isa = XCBuildConfiguration; 700 | buildSettings = { 701 | CLANG_ENABLE_OBJC_WEAK = YES; 702 | PRODUCT_NAME = SMJobKitTemplate; 703 | }; 704 | name = Debug; 705 | }; 706 | 3CCC06D315AA823000C84BE1 /* Release */ = { 707 | isa = XCBuildConfiguration; 708 | buildSettings = { 709 | CLANG_ENABLE_OBJC_WEAK = YES; 710 | PRODUCT_NAME = SMJobKitTemplate; 711 | }; 712 | name = Release; 713 | }; 714 | /* End XCBuildConfiguration section */ 715 | 716 | /* Begin XCConfigurationList section */ 717 | 3C2BFAB815AB33020011FA52 /* Build configuration list for PBXNativeTarget "TestService" */ = { 718 | isa = XCConfigurationList; 719 | buildConfigurations = ( 720 | 3C2BFAB915AB33020011FA52 /* Debug */, 721 | 3C2BFABA15AB33020011FA52 /* Release */, 722 | ); 723 | defaultConfigurationIsVisible = 0; 724 | defaultConfigurationName = Release; 725 | }; 726 | 3CA1506A15A91179001CF9F8 /* Build configuration list for PBXProject "SMJobKit" */ = { 727 | isa = XCConfigurationList; 728 | buildConfigurations = ( 729 | 3CA1509915A91179001CF9F8 /* Debug */, 730 | 3CA1509A15A91179001CF9F8 /* Release */, 731 | ); 732 | defaultConfigurationIsVisible = 0; 733 | defaultConfigurationName = Release; 734 | }; 735 | 3CA1509B15A91179001CF9F8 /* Build configuration list for PBXNativeTarget "SMJobKit" */ = { 736 | isa = XCConfigurationList; 737 | buildConfigurations = ( 738 | 3CA1509C15A91179001CF9F8 /* Debug */, 739 | 3CA1509D15A91179001CF9F8 /* Release */, 740 | ); 741 | defaultConfigurationIsVisible = 0; 742 | defaultConfigurationName = Release; 743 | }; 744 | 3CA1509E15A91179001CF9F8 /* Build configuration list for PBXNativeTarget "SMJobKitTests" */ = { 745 | isa = XCConfigurationList; 746 | buildConfigurations = ( 747 | 3CA1509F15A91179001CF9F8 /* Debug */, 748 | 3CA150A015A91179001CF9F8 /* Release */, 749 | ); 750 | defaultConfigurationIsVisible = 0; 751 | defaultConfigurationName = Release; 752 | }; 753 | 3CCC06D115AA823000C84BE1 /* Build configuration list for PBXAggregateTarget "Xcode Templates" */ = { 754 | isa = XCConfigurationList; 755 | buildConfigurations = ( 756 | 3CCC06D215AA823000C84BE1 /* Debug */, 757 | 3CCC06D315AA823000C84BE1 /* Release */, 758 | ); 759 | defaultConfigurationIsVisible = 0; 760 | defaultConfigurationName = Release; 761 | }; 762 | /* End XCConfigurationList section */ 763 | }; 764 | rootObject = 3CA1506715A91179001CF9F8 /* Project object */; 765 | } 766 | -------------------------------------------------------------------------------- /SMJobKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SMJobKit.xcodeproj/project.xcworkspace/xcshareddata/SMJobKit.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 83F83DB4-C14B-4167-820F-258BD46D7259 9 | IDESourceControlProjectName 10 | project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 62999A12ECFCEE422C7E9695EF797E99914609D9 14 | https://github.com/IngmarStein/SMJobKit.git 15 | 16 | IDESourceControlProjectPath 17 | SMJobKit.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 62999A12ECFCEE422C7E9695EF797E99914609D9 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/IngmarStein/SMJobKit.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 62999A12ECFCEE422C7E9695EF797E99914609D9 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 62999A12ECFCEE422C7E9695EF797E99914609D9 36 | IDESourceControlWCCName 37 | SMJobKit 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SMJobKit.xcodeproj/xcshareddata/xcschemes/SMJobKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 63 | 69 | 70 | 71 | 72 | 78 | 79 | 85 | 86 | 87 | 88 | 90 | 91 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /SMJobKit.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SMJobKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SMJobKit.xcworkspace/xcshareddata/SMJobKit.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 5DAC43F9-C716-4349-8B0F-ABB94D1AFD46 9 | IDESourceControlProjectName 10 | SMJobKit 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 62999A12ECFCEE422C7E9695EF797E99914609D9 14 | https://github.com/IngmarStein/SMJobKit.git 15 | 16 | IDESourceControlProjectPath 17 | SMJobKit.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 62999A12ECFCEE422C7E9695EF797E99914609D9 21 | .. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/IngmarStein/SMJobKit.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 62999A12ECFCEE422C7E9695EF797E99914609D9 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 62999A12ECFCEE422C7E9695EF797E99914609D9 36 | IDESourceControlWCCName 37 | SMJobKit 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SampleApplication/SampleApplication.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 47; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3CE185A515C64C1000A8FB57 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3CE185A315C64C1000A8FB57 /* InfoPlist.strings */; }; 11 | 3CE185AB15C64C1000A8FB57 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 3CE185A915C64C1000A8FB57 /* Credits.rtf */; }; 12 | 3CE185B115C64C1000A8FB57 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3CE185AF15C64C1000A8FB57 /* MainMenu.xib */; }; 13 | 3CE185C415C64C1000A8FB57 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CE185C315C64C1000A8FB57 /* main.m */; }; 14 | 3CE185CF15C64C2A00A8FB57 /* net.nevir.SMJobKit.SampleApplication.SampleService in Copy Services */ = {isa = PBXBuildFile; fileRef = 3CE185BC15C64C1000A8FB57 /* net.nevir.SMJobKit.SampleApplication.SampleService */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 15 | 3CE185D115C64CA500A8FB57 /* SMJobKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE185D015C64CA500A8FB57 /* SMJobKit.framework */; }; 16 | 9591AC7F1AC88345000C58EC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9591AC7E1AC88345000C58EC /* AppDelegate.swift */; }; 17 | 9591AC811AC8858E000C58EC /* SampleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9591AC801AC8858E000C58EC /* SampleService.swift */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | 3CE185BE15C64C1000A8FB57 /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = 3CE1858B15C64C1000A8FB57 /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = 3CE185BB15C64C1000A8FB57; 26 | remoteInfo = SampleService; 27 | }; 28 | /* End PBXContainerItemProxy section */ 29 | 30 | /* Begin PBXCopyFilesBuildPhase section */ 31 | 3CE1859415C64C1000A8FB57 /* Copy Services */ = { 32 | isa = PBXCopyFilesBuildPhase; 33 | buildActionMask = 2147483647; 34 | dstPath = Contents/Library/LaunchServices; 35 | dstSubfolderSpec = 1; 36 | files = ( 37 | 3CE185CF15C64C2A00A8FB57 /* net.nevir.SMJobKit.SampleApplication.SampleService in Copy Services */, 38 | ); 39 | name = "Copy Services"; 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXCopyFilesBuildPhase section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 3CE1859615C64C1000A8FB57 /* SampleApplication.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SampleApplication.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 3CE185A215C64C1000A8FB57 /* SampleApplication-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SampleApplication-Info.plist"; sourceTree = ""; }; 47 | 3CE185A415C64C1000A8FB57 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 48 | 3CE185AA15C64C1000A8FB57 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 49 | 3CE185BC15C64C1000A8FB57 /* net.nevir.SMJobKit.SampleApplication.SampleService */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = net.nevir.SMJobKit.SampleApplication.SampleService; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 3CE185C315C64C1000A8FB57 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | 3CE185C515C64C1000A8FB57 /* SampleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SampleService-Info.plist"; sourceTree = ""; }; 52 | 3CE185C615C64C1000A8FB57 /* SampleService-Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SampleService-Launchd.plist"; sourceTree = ""; }; 53 | 3CE185D015C64CA500A8FB57 /* SMJobKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SMJobKit.framework; path = "../../../Library/Developer/Xcode/DerivedData/SMJobKit-fliesfietiliwshiebehkxithcjq/Build/Products/Debug/SMJobKit.framework"; sourceTree = ""; }; 54 | 3CE185D215C64CAA00A8FB57 /* libSMJService.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSMJService.a; path = "../../../Library/Developer/Xcode/DerivedData/SMJobKit-fliesfietiliwshiebehkxithcjq/Build/Products/Debug/libSMJService.a"; sourceTree = ""; }; 55 | 957C3A4D22652F030092A8F5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 56 | 9591AC7D1AC88345000C58EC /* SampleApplication-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SampleApplication-Bridging-Header.h"; sourceTree = ""; }; 57 | 9591AC7E1AC88345000C58EC /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 58 | 9591AC801AC8858E000C58EC /* SampleService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleService.swift; sourceTree = ""; }; 59 | /* End PBXFileReference section */ 60 | 61 | /* Begin PBXFrameworksBuildPhase section */ 62 | 3CE1859115C64C1000A8FB57 /* Frameworks */ = { 63 | isa = PBXFrameworksBuildPhase; 64 | buildActionMask = 2147483647; 65 | files = ( 66 | 3CE185D115C64CA500A8FB57 /* SMJobKit.framework in Frameworks */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 3CE185BA15C64C1000A8FB57 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | /* End PBXFrameworksBuildPhase section */ 78 | 79 | /* Begin PBXGroup section */ 80 | 3CE1858915C64C1000A8FB57 = { 81 | isa = PBXGroup; 82 | children = ( 83 | 3CE185A015C64C1000A8FB57 /* SampleApplication */, 84 | 3CE185C215C64C1000A8FB57 /* SampleService */, 85 | 3CE1859915C64C1000A8FB57 /* Frameworks */, 86 | 3CE1859715C64C1000A8FB57 /* Products */, 87 | ); 88 | sourceTree = ""; 89 | }; 90 | 3CE1859715C64C1000A8FB57 /* Products */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 3CE1859615C64C1000A8FB57 /* SampleApplication.app */, 94 | 3CE185BC15C64C1000A8FB57 /* net.nevir.SMJobKit.SampleApplication.SampleService */, 95 | ); 96 | name = Products; 97 | sourceTree = ""; 98 | }; 99 | 3CE1859915C64C1000A8FB57 /* Frameworks */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 3CE185D215C64CAA00A8FB57 /* libSMJService.a */, 103 | 3CE185D015C64CA500A8FB57 /* SMJobKit.framework */, 104 | ); 105 | name = Frameworks; 106 | sourceTree = ""; 107 | }; 108 | 3CE185A015C64C1000A8FB57 /* SampleApplication */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 9591AC7E1AC88345000C58EC /* AppDelegate.swift */, 112 | 3CE185AF15C64C1000A8FB57 /* MainMenu.xib */, 113 | 3CE185B415C64C1000A8FB57 /* Service Clients */, 114 | 3CE185A115C64C1000A8FB57 /* Supporting Files */, 115 | ); 116 | path = SampleApplication; 117 | sourceTree = ""; 118 | }; 119 | 3CE185A115C64C1000A8FB57 /* Supporting Files */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 3CE185A915C64C1000A8FB57 /* Credits.rtf */, 123 | 3CE185A315C64C1000A8FB57 /* InfoPlist.strings */, 124 | 9591AC7D1AC88345000C58EC /* SampleApplication-Bridging-Header.h */, 125 | 3CE185A215C64C1000A8FB57 /* SampleApplication-Info.plist */, 126 | ); 127 | name = "Supporting Files"; 128 | sourceTree = ""; 129 | }; 130 | 3CE185B415C64C1000A8FB57 /* Service Clients */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 9591AC801AC8858E000C58EC /* SampleService.swift */, 134 | ); 135 | name = "Service Clients"; 136 | sourceTree = ""; 137 | }; 138 | 3CE185C215C64C1000A8FB57 /* SampleService */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 3CE185C315C64C1000A8FB57 /* main.m */, 142 | 3CE185C515C64C1000A8FB57 /* SampleService-Info.plist */, 143 | 3CE185C615C64C1000A8FB57 /* SampleService-Launchd.plist */, 144 | ); 145 | path = SampleService; 146 | sourceTree = ""; 147 | }; 148 | /* End PBXGroup section */ 149 | 150 | /* Begin PBXNativeTarget section */ 151 | 3CE1859515C64C1000A8FB57 /* SampleApplication */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = 3CE185CC15C64C1000A8FB57 /* Build configuration list for PBXNativeTarget "SampleApplication" */; 154 | buildPhases = ( 155 | 3CE1859015C64C1000A8FB57 /* Sources */, 156 | 3CE1859115C64C1000A8FB57 /* Frameworks */, 157 | 3CE1859215C64C1000A8FB57 /* Resources */, 158 | 3CE1859415C64C1000A8FB57 /* Copy Services */, 159 | ); 160 | buildRules = ( 161 | ); 162 | dependencies = ( 163 | 3CE185BF15C64C1000A8FB57 /* PBXTargetDependency */, 164 | ); 165 | name = SampleApplication; 166 | productName = SampleApplication; 167 | productReference = 3CE1859615C64C1000A8FB57 /* SampleApplication.app */; 168 | productType = "com.apple.product-type.application"; 169 | }; 170 | 3CE185BB15C64C1000A8FB57 /* SampleService */ = { 171 | isa = PBXNativeTarget; 172 | buildConfigurationList = 3CE185C915C64C1000A8FB57 /* Build configuration list for PBXNativeTarget "SampleService" */; 173 | buildPhases = ( 174 | 3CE185B815C64C1000A8FB57 /* Preprocess Resources */, 175 | 3CE185B915C64C1000A8FB57 /* Sources */, 176 | 3CE185BA15C64C1000A8FB57 /* Frameworks */, 177 | ); 178 | buildRules = ( 179 | ); 180 | dependencies = ( 181 | ); 182 | name = SampleService; 183 | productName = SampleService; 184 | productReference = 3CE185BC15C64C1000A8FB57 /* net.nevir.SMJobKit.SampleApplication.SampleService */; 185 | productType = "com.apple.product-type.tool"; 186 | }; 187 | /* End PBXNativeTarget section */ 188 | 189 | /* Begin PBXProject section */ 190 | 3CE1858B15C64C1000A8FB57 /* Project object */ = { 191 | isa = PBXProject; 192 | attributes = { 193 | LastSwiftUpdateCheck = 0700; 194 | LastUpgradeCheck = 1100; 195 | ORGANIZATIONNAME = "Ingmar Stein"; 196 | }; 197 | buildConfigurationList = 3CE1858E15C64C1000A8FB57 /* Build configuration list for PBXProject "SampleApplication" */; 198 | compatibilityVersion = "Xcode 6.3"; 199 | developmentRegion = en; 200 | hasScannedForEncodings = 0; 201 | knownRegions = ( 202 | en, 203 | Base, 204 | ); 205 | mainGroup = 3CE1858915C64C1000A8FB57; 206 | productRefGroup = 3CE1859715C64C1000A8FB57 /* Products */; 207 | projectDirPath = ""; 208 | projectRoot = ""; 209 | targets = ( 210 | 3CE1859515C64C1000A8FB57 /* SampleApplication */, 211 | 3CE185BB15C64C1000A8FB57 /* SampleService */, 212 | ); 213 | }; 214 | /* End PBXProject section */ 215 | 216 | /* Begin PBXResourcesBuildPhase section */ 217 | 3CE1859215C64C1000A8FB57 /* Resources */ = { 218 | isa = PBXResourcesBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | 3CE185A515C64C1000A8FB57 /* InfoPlist.strings in Resources */, 222 | 3CE185AB15C64C1000A8FB57 /* Credits.rtf in Resources */, 223 | 3CE185B115C64C1000A8FB57 /* MainMenu.xib in Resources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXResourcesBuildPhase section */ 228 | 229 | /* Begin PBXShellScriptBuildPhase section */ 230 | 3CE185B815C64C1000A8FB57 /* Preprocess Resources */ = { 231 | isa = PBXShellScriptBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | ); 235 | inputPaths = ( 236 | ); 237 | name = "Preprocess Resources"; 238 | outputPaths = ( 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | shellPath = "/usr/bin/env ruby"; 242 | shellScript = "# Generic preprocessing for ${ENV_VAR} with output to the build dir.\n\nrequire 'cgi'\nrequire 'fileutils'\n\nmissing_keys = ['BUILD_DIR', 'CODE_SIGN_IDENTITY', 'SMJ_PREPROCESS_FILES', 'SMJ_PREPROCESS_DIR'] - ENV.keys\nraise \"Missing required ENV values: #{missing_keys.inspect}\" if missing_keys.size > 0\n\n# SMJ_PREPROCESS_FILES is a comma-separated list of *relative* file paths to preprocess\n# and spit out into the SMJ_PREPROCESS_DIR (w/ the same relative paths as given)\nfiles_to_preprocess = ENV['SMJ_PREPROCESS_FILES'].split(',').map(&:strip)\n\n\n# Environment Cleanup\n# -------------------\ndummy_path = \"#{ENV['BUILD_DIR']}/SMJobKitCodeSigningDummy\"\n\nidentity = ENV['CODE_SIGN_IDENTITY']\n# If you use the generic code signing identity, chances are that it'll conflict.\nidentity = \"#{identity}:\" if identity.end_with? ' Developer'\n\n# We can't seem to get direct access to the code signing certificate that Xcode has\n# selected at this point :(\n`touch #{dummy_path}`\n`codesign --force --sign \"#{identity}\" \"#{dummy_path}\"`\nresult = `codesign --display --verbose --verbose \"#{dummy_path}\" 2>&1`\n`rm #{dummy_path}`\n\nENV['FULL_CODE_SIGN_IDENTITY'] = result[/Authority\\=(.*#{Regexp.escape(identity)}.*)/, 1]\n\n\n# Actual Preprocessing\n# --------------------\n\nfiles_to_preprocess.each do |path|\n target_path = File.join(ENV['SMJ_PREPROCESS_DIR'], path)\n FileUtils.mkpath File.dirname(target_path)\n\n open(path) do |input|\n open(target_path, 'w') do |output|\n # Specify macros via ${VAR_NAME} in the preprocessed file. Same as regular\n # Info.plist preprocessing.\n output.write input.read.gsub(/\\$\\{([A-Z_]+)\\}/) { CGI.escapeHTML(ENV[$1]) }\n end\n puts target_path\n end\nend"; 243 | }; 244 | /* End PBXShellScriptBuildPhase section */ 245 | 246 | /* Begin PBXSourcesBuildPhase section */ 247 | 3CE1859015C64C1000A8FB57 /* Sources */ = { 248 | isa = PBXSourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | 9591AC7F1AC88345000C58EC /* AppDelegate.swift in Sources */, 252 | 9591AC811AC8858E000C58EC /* SampleService.swift in Sources */, 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | }; 256 | 3CE185B915C64C1000A8FB57 /* Sources */ = { 257 | isa = PBXSourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 3CE185C415C64C1000A8FB57 /* main.m in Sources */, 261 | ); 262 | runOnlyForDeploymentPostprocessing = 0; 263 | }; 264 | /* End PBXSourcesBuildPhase section */ 265 | 266 | /* Begin PBXTargetDependency section */ 267 | 3CE185BF15C64C1000A8FB57 /* PBXTargetDependency */ = { 268 | isa = PBXTargetDependency; 269 | target = 3CE185BB15C64C1000A8FB57 /* SampleService */; 270 | targetProxy = 3CE185BE15C64C1000A8FB57 /* PBXContainerItemProxy */; 271 | }; 272 | /* End PBXTargetDependency section */ 273 | 274 | /* Begin PBXVariantGroup section */ 275 | 3CE185A315C64C1000A8FB57 /* InfoPlist.strings */ = { 276 | isa = PBXVariantGroup; 277 | children = ( 278 | 3CE185A415C64C1000A8FB57 /* en */, 279 | ); 280 | name = InfoPlist.strings; 281 | sourceTree = ""; 282 | }; 283 | 3CE185A915C64C1000A8FB57 /* Credits.rtf */ = { 284 | isa = PBXVariantGroup; 285 | children = ( 286 | 3CE185AA15C64C1000A8FB57 /* en */, 287 | ); 288 | name = Credits.rtf; 289 | sourceTree = ""; 290 | }; 291 | 3CE185AF15C64C1000A8FB57 /* MainMenu.xib */ = { 292 | isa = PBXVariantGroup; 293 | children = ( 294 | 957C3A4D22652F030092A8F5 /* Base */, 295 | ); 296 | name = MainMenu.xib; 297 | sourceTree = ""; 298 | }; 299 | /* End PBXVariantGroup section */ 300 | 301 | /* Begin XCBuildConfiguration section */ 302 | 3CE185C715C64C1000A8FB57 /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 323 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 324 | CLANG_WARN_STRICT_PROTOTYPES = YES; 325 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 326 | CLANG_WARN_UNREACHABLE_CODE = YES; 327 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 328 | COPY_PHASE_STRIP = NO; 329 | ENABLE_STRICT_OBJC_MSGSEND = YES; 330 | ENABLE_TESTABILITY = YES; 331 | GCC_C_LANGUAGE_STANDARD = gnu99; 332 | GCC_DYNAMIC_NO_PIC = NO; 333 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 334 | GCC_NO_COMMON_BLOCKS = YES; 335 | GCC_OPTIMIZATION_LEVEL = 0; 336 | GCC_PREPROCESSOR_DEFINITIONS = ( 337 | "DEBUG=1", 338 | "$(inherited)", 339 | ); 340 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 341 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 342 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 343 | GCC_WARN_UNDECLARED_SELECTOR = YES; 344 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 345 | GCC_WARN_UNUSED_FUNCTION = YES; 346 | GCC_WARN_UNUSED_VARIABLE = YES; 347 | MACOSX_DEPLOYMENT_TARGET = 10.9; 348 | ONLY_ACTIVE_ARCH = YES; 349 | SDKROOT = macosx; 350 | }; 351 | name = Debug; 352 | }; 353 | 3CE185C815C64C1000A8FB57 /* Release */ = { 354 | isa = XCBuildConfiguration; 355 | buildSettings = { 356 | ALWAYS_SEARCH_USER_PATHS = NO; 357 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 358 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 359 | CLANG_CXX_LIBRARY = "libc++"; 360 | CLANG_ENABLE_MODULES = YES; 361 | CLANG_ENABLE_OBJC_ARC = YES; 362 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 363 | CLANG_WARN_BOOL_CONVERSION = YES; 364 | CLANG_WARN_COMMA = YES; 365 | CLANG_WARN_CONSTANT_CONVERSION = YES; 366 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 367 | CLANG_WARN_EMPTY_BODY = YES; 368 | CLANG_WARN_ENUM_CONVERSION = YES; 369 | CLANG_WARN_INFINITE_RECURSION = YES; 370 | CLANG_WARN_INT_CONVERSION = YES; 371 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 372 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 373 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 374 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 375 | CLANG_WARN_STRICT_PROTOTYPES = YES; 376 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 377 | CLANG_WARN_UNREACHABLE_CODE = YES; 378 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 379 | COPY_PHASE_STRIP = YES; 380 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 381 | ENABLE_STRICT_OBJC_MSGSEND = YES; 382 | GCC_C_LANGUAGE_STANDARD = gnu99; 383 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 384 | GCC_NO_COMMON_BLOCKS = YES; 385 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 386 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 387 | GCC_WARN_UNDECLARED_SELECTOR = YES; 388 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 389 | GCC_WARN_UNUSED_FUNCTION = YES; 390 | GCC_WARN_UNUSED_VARIABLE = YES; 391 | MACOSX_DEPLOYMENT_TARGET = 10.9; 392 | SDKROOT = macosx; 393 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 394 | }; 395 | name = Release; 396 | }; 397 | 3CE185CA15C64C1000A8FB57 /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | CODE_SIGN_IDENTITY = "Developer ID Application"; 401 | ENABLE_HARDENED_RUNTIME = YES; 402 | OTHER_LDFLAGS = ( 403 | "-sectcreate", 404 | __TEXT, 405 | __info_plist, 406 | "\"$(SMJ_PREPROCESS_DIR)/SampleService/SampleService-Info.plist\"", 407 | "-sectcreate", 408 | __TEXT, 409 | __launchd_plist, 410 | "\"$(SMJ_PREPROCESS_DIR)/SampleService/SampleService-Launchd.plist\"", 411 | ); 412 | PARENT_APPLICATION_IDENTIFIER = "net.nevir.SMJobKit.$(PROJECT_NAME)"; 413 | PRODUCT_NAME = "net.nevir.SMJobKit.$(PROJECT_NAME).$(TARGET_NAME)"; 414 | SMJ_PREPROCESS_DIR = "$(BUILD_DIR)/Preprocessed"; 415 | SMJ_PREPROCESS_FILES = "SampleService/SampleService-Info.plist, SampleService/SampleService-Launchd.plist"; 416 | }; 417 | name = Debug; 418 | }; 419 | 3CE185CB15C64C1000A8FB57 /* Release */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | CODE_SIGN_IDENTITY = "Developer ID Application"; 423 | ENABLE_HARDENED_RUNTIME = YES; 424 | OTHER_LDFLAGS = ( 425 | "-sectcreate", 426 | __TEXT, 427 | __info_plist, 428 | "\"$(SMJ_PREPROCESS_DIR)/SampleService/SampleService-Info.plist\"", 429 | "-sectcreate", 430 | __TEXT, 431 | __launchd_plist, 432 | "\"$(SMJ_PREPROCESS_DIR)/SampleService/SampleService-Launchd.plist\"", 433 | ); 434 | PARENT_APPLICATION_IDENTIFIER = "net.nevir.SMJobKit.$(PROJECT_NAME)"; 435 | PRODUCT_NAME = "net.nevir.SMJobKit.$(PROJECT_NAME).$(TARGET_NAME)"; 436 | SMJ_PREPROCESS_DIR = "$(BUILD_DIR)/Preprocessed"; 437 | SMJ_PREPROCESS_FILES = "SampleService/SampleService-Info.plist, SampleService/SampleService-Launchd.plist"; 438 | }; 439 | name = Release; 440 | }; 441 | 3CE185CD15C64C1000A8FB57 /* Debug */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | CLANG_ENABLE_MODULES = YES; 445 | CODE_SIGN_IDENTITY = "Developer ID Application"; 446 | COMBINE_HIDPI_IMAGES = YES; 447 | ENABLE_HARDENED_RUNTIME = YES; 448 | INFOPLIST_FILE = "SampleApplication/SampleApplication-Info.plist"; 449 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 450 | PRODUCT_BUNDLE_IDENTIFIER = "net.nevir.SMJobKit.${PRODUCT_NAME:rfc1034identifier}"; 451 | PRODUCT_NAME = "$(TARGET_NAME)"; 452 | SWIFT_OBJC_BRIDGING_HEADER = "SampleApplication/SampleApplication-Bridging-Header.h"; 453 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 454 | SWIFT_VERSION = 4.2; 455 | WRAPPER_EXTENSION = app; 456 | }; 457 | name = Debug; 458 | }; 459 | 3CE185CE15C64C1000A8FB57 /* Release */ = { 460 | isa = XCBuildConfiguration; 461 | buildSettings = { 462 | CLANG_ENABLE_MODULES = YES; 463 | CODE_SIGN_IDENTITY = "Developer ID Application"; 464 | COMBINE_HIDPI_IMAGES = YES; 465 | ENABLE_HARDENED_RUNTIME = YES; 466 | INFOPLIST_FILE = "SampleApplication/SampleApplication-Info.plist"; 467 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 468 | PRODUCT_BUNDLE_IDENTIFIER = "net.nevir.SMJobKit.${PRODUCT_NAME:rfc1034identifier}"; 469 | PRODUCT_NAME = "$(TARGET_NAME)"; 470 | SWIFT_OBJC_BRIDGING_HEADER = "SampleApplication/SampleApplication-Bridging-Header.h"; 471 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 472 | SWIFT_VERSION = 4.2; 473 | WRAPPER_EXTENSION = app; 474 | }; 475 | name = Release; 476 | }; 477 | /* End XCBuildConfiguration section */ 478 | 479 | /* Begin XCConfigurationList section */ 480 | 3CE1858E15C64C1000A8FB57 /* Build configuration list for PBXProject "SampleApplication" */ = { 481 | isa = XCConfigurationList; 482 | buildConfigurations = ( 483 | 3CE185C715C64C1000A8FB57 /* Debug */, 484 | 3CE185C815C64C1000A8FB57 /* Release */, 485 | ); 486 | defaultConfigurationIsVisible = 0; 487 | defaultConfigurationName = Release; 488 | }; 489 | 3CE185C915C64C1000A8FB57 /* Build configuration list for PBXNativeTarget "SampleService" */ = { 490 | isa = XCConfigurationList; 491 | buildConfigurations = ( 492 | 3CE185CA15C64C1000A8FB57 /* Debug */, 493 | 3CE185CB15C64C1000A8FB57 /* Release */, 494 | ); 495 | defaultConfigurationIsVisible = 0; 496 | defaultConfigurationName = Release; 497 | }; 498 | 3CE185CC15C64C1000A8FB57 /* Build configuration list for PBXNativeTarget "SampleApplication" */ = { 499 | isa = XCConfigurationList; 500 | buildConfigurations = ( 501 | 3CE185CD15C64C1000A8FB57 /* Debug */, 502 | 3CE185CE15C64C1000A8FB57 /* Release */, 503 | ); 504 | defaultConfigurationIsVisible = 0; 505 | defaultConfigurationName = Release; 506 | }; 507 | /* End XCConfigurationList section */ 508 | }; 509 | rootObject = 3CE1858B15C64C1000A8FB57 /* Project object */; 510 | } 511 | -------------------------------------------------------------------------------- /SampleApplication/SampleApplication/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SampleApplication 4 | // 5 | // Created by Ingmar Stein on 29.03.15. 6 | // Copyright (c) 2015 Ian MacLeod. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | @IBOutlet private weak var window: NSWindow! 14 | @IBOutlet private var outputTextView: NSTextView! 15 | @IBOutlet private weak var bundledVersionLabel: NSTextField! 16 | 17 | func applicationDidFinishLaunching(_ notification: Notification) { 18 | updateStatus() 19 | } 20 | 21 | private func appendMessage(_ message: String) { 22 | self.outputTextView.string! += "\(message)\n" 23 | } 24 | 25 | @IBAction func installService(sender: AnyObject!) { 26 | // In order to test out SMJobKit, 27 | // SampleApplication is trying to install a new 28 | // helper tool. Type your password to allow this. 29 | do { 30 | try SampleService.installWithPrompt(prompt: "In order to test out SMJobKit,") 31 | appendMessage("Successfully installed SampleService") 32 | } catch let error { 33 | appendMessage("\(error)") 34 | } 35 | 36 | updateStatus() 37 | } 38 | 39 | private func updateStatus() { 40 | self.bundledVersionLabel.stringValue = SampleService.bundledVersion ?? "Unknown Version" 41 | 42 | SampleService.checkForProblems().map { self.appendMessage("\($0)") } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /SampleApplication/SampleApplication/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | Default 524 | 525 | 526 | 527 | 528 | 529 | 530 | Left to Right 531 | 532 | 533 | 534 | 535 | 536 | 537 | Right to Left 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | Default 549 | 550 | 551 | 552 | 553 | 554 | 555 | Left to Right 556 | 557 | 558 | 559 | 560 | 561 | 562 | Right to Left 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | -------------------------------------------------------------------------------- /SampleApplication/SampleApplication/SampleApplication-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /SampleApplication/SampleApplication/SampleApplication-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSMinimumSystemVersion 28 | ${MACOSX_DEPLOYMENT_TARGET} 29 | NSHumanReadableCopyright 30 | Copyright © 2012 Ian MacLeod. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | SMPrivilegedExecutables 36 | 37 | net.nevir.SMJobKit.[[[PROJECT_NAME]]].SampleService 38 | identifier net.nevir.SMJobKit.[[[PROJECT_NAME]]].SampleService and certificate leaf[subject.CN] = "[[[FULL_CODE_SIGN_IDENTITY]]]" 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SampleApplication/SampleApplication/SampleService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SampleService.swift 3 | // SampleApplication 4 | // 5 | // Created by Ingmar Stein on 29.03.15. 6 | // Copyright (c) 2015 Ian MacLeod. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import SMJobKit 11 | 12 | class SampleService: Client { 13 | override class var serviceIdentifier: String { 14 | return "net.nevir.SMJobKit.SampleApplication.SampleService" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SampleApplication/SampleApplication/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /SampleApplication/SampleApplication/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SampleApplication/SampleService/SampleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | ${PRODUCT_NAME} 7 | CFBundleInfoDictionaryVersion 8 | 6.0 9 | CFBundleName 10 | SampleService 11 | CFBundleVersion 12 | 0.01 13 | SMAuthorizedClients 14 | 15 | identifier ${PARENT_APPLICATION_IDENTIFIER} and certificate leaf[subject.CN] = "${FULL_CODE_SIGN_IDENTITY}" 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SampleApplication/SampleService/SampleService-Launchd.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | ${PRODUCT_NAME} 7 | MachServices 8 | 9 | ${PRODUCT_NAME} 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /SampleApplication/SampleService/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SampleService 4 | // 5 | // Created by Ian MacLeod on 7/29/12. 6 | // Copyright (c) 2012 Ian MacLeod. All rights reserved. 7 | // 8 | 9 | int main(int argc, const char *argv[]) 10 | { 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /Sources/SMJobKit/BridgingHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // BridgingHeader.h 3 | // SMJobKit 4 | // 5 | // Created by Ingmar Stein on 30.08.15. 6 | // 7 | // 8 | 9 | #import 10 | -------------------------------------------------------------------------------- /Sources/SMJobKit/Client.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Client.swift 3 | // SMJobKit 4 | // 5 | // Created by Ingmar Stein on 29.03.15. 6 | // 7 | // 8 | 9 | import Foundation 10 | import ServiceManagement 11 | 12 | open class Client { 13 | 14 | // MARK: - Abstract Interface 15 | 16 | open class var serviceIdentifier: String { 17 | fatalError("You need to implement serviceIdentifier!") 18 | } 19 | 20 | // MARK: - Public Interface 21 | 22 | public class var bundledVersion: String? { 23 | return try? ClientUtility.versionForBundlePath(bundledServicePath) 24 | } 25 | 26 | public class func installWithPrompt(prompt: String?) throws { 27 | let authRef = try ClientUtility.authWithRight(kSMRightBlessPrivilegedHelper, prompt: prompt) 28 | 29 | // Here's the good stuff 30 | var cfError: Unmanaged? 31 | if !SMJobBless(kSMDomainSystemLaunchd, cfIdentifier, authRef, &cfError) { 32 | let blessError = cfError!.takeRetainedValue() 33 | throw SMJError.unableToBless(blessError) // String(format: "SMJobBless failure (code %ld): %@", blessError.code, blessError.localizedDescription) 34 | } 35 | 36 | NSLog("%@ (%@) installed successfully", serviceIdentifier as NSString, bundledVersion! as NSString) 37 | } 38 | 39 | // MARK: - Diagnostics 40 | 41 | public class func checkForProblems() -> [Error] { 42 | var errors = [Error]() 43 | 44 | do { 45 | try _ = ClientUtility.versionForBundlePath(bundledServicePath) 46 | } catch let error { 47 | errors.append(error) 48 | } 49 | 50 | return errors 51 | } 52 | 53 | // MARK: - Service Information 54 | 55 | public class var bundledServicePath: String { 56 | let helperRelative = "Contents/Library/LaunchServices/\(serviceIdentifier)" 57 | 58 | return (Bundle(for: self).bundlePath as NSString).appendingPathComponent(helperRelative) 59 | } 60 | 61 | // MARK: - Utility 62 | 63 | private class var cfIdentifier: CFString { 64 | return serviceIdentifier as CFString 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /Sources/SMJobKit/ClientUtility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClientUtility.swift 3 | // SMJobKit 4 | // 5 | // Created by Ingmar Stein on 29.03.15. 6 | // 7 | // 8 | 9 | import Foundation 10 | import Security 11 | 12 | final class ClientUtility { 13 | 14 | // MARK: - Bundle Introspection 15 | 16 | static func versionForBundlePath(_ bundlePath: String) throws -> String { 17 | // We can't use CFBundleCopyInfoDictionaryForURL, as it breaks our code signing validity. 18 | var codeRef: SecStaticCode? 19 | 20 | let url = NSURL(fileURLWithPath: bundlePath, isDirectory: false) 21 | let result = SecStaticCodeCreateWithPath(url, [], &codeRef) 22 | if result == noErr, let code = codeRef { 23 | var codeInfoRef: CFDictionary? 24 | let result2 = SecCodeCopySigningInformation(code, [], &codeInfoRef) 25 | if result2 == noErr, let codeInfo = codeInfoRef { 26 | let codeInfoDictionary = codeInfo as [NSObject: AnyObject] 27 | if let bundleInfo = codeInfoDictionary[kSecCodeInfoPList] as? [String: AnyObject] { 28 | if let value = bundleInfo["CFBundleVersion"] as? String { 29 | return value 30 | } else { 31 | throw SMJError.badBundleCodeSigningDictionary // "CFBundleVersion was not a string" 32 | } 33 | } else { 34 | throw SMJError.badBundleCodeSigningDictionary // "kSecCodeInfoPList was not a dictionary" 35 | } 36 | } else { 37 | throw SMJError.badBundleCodeSigningDictionary // String(format: "Failed to read code signing dictionary (OSStatus %d)", result2) 38 | } 39 | } else { 40 | if result == OSStatus(errSecCSUnsigned) { 41 | throw SMJError.unsignedBundle // "Encountered unsigned bundle" 42 | } else if result == OSStatus(errSecCSStaticCodeNotFound) { 43 | throw SMJError.bundleNotFound // "No bundle found at given path" 44 | } else { 45 | throw SMJError.badBundleSecurity(result) // String(format: "Failed to create SecStaticCodeRef (OSStatus %d)", result) 46 | } 47 | } 48 | } 49 | 50 | // MARK: - Authorization & Security 51 | 52 | static func authWithRight(_ rightName: String, prompt: String?) throws -> AuthorizationRef { 53 | let authorizationRight = (rightName as NSString).utf8String! 54 | let authItem = AuthorizationItem(name: authorizationRight, valueLength: 0, value: nil, flags: 0) 55 | let authItemPointer = UnsafeMutablePointer.allocate(capacity: 1) 56 | authItemPointer.initialize(to: authItem) 57 | defer { 58 | authItemPointer.deinitialize(count: 1) 59 | authItemPointer.deallocate() 60 | } 61 | var authRights = AuthorizationRights(count: 1, items: authItemPointer) 62 | 63 | var environment = AuthorizationEnvironment(count: 0, items: nil) 64 | 65 | if let prompt = prompt { 66 | let authorizationEnvironmentPrompt = (kAuthorizationEnvironmentPrompt as NSString).utf8String! 67 | let promptString = (prompt as NSString).utf8String! 68 | let envItem = AuthorizationItem(name: authorizationEnvironmentPrompt, valueLength: prompt.lengthOfBytes(using: String.Encoding.utf8), value: UnsafeMutablePointer(mutating: promptString), flags: UInt32(0)) 69 | let envItemPointer = UnsafeMutablePointer.allocate(capacity: 1) 70 | envItemPointer.initialize(to: envItem) 71 | environment.count = 1 72 | environment.items = envItemPointer 73 | } 74 | 75 | let flags: AuthorizationFlags = [ 76 | .interactionAllowed, 77 | .preAuthorize, 78 | .extendRights 79 | ] 80 | 81 | var authRef: AuthorizationRef? 82 | let status = AuthorizationCreate(&authRights, &environment, flags, &authRef) 83 | if let envItems = environment.items { 84 | envItems.deinitialize(count: Int(environment.count)) 85 | envItems.deallocate() 86 | } 87 | if status == OSStatus(errAuthorizationSuccess) { 88 | return authRef! 89 | } else if status == OSStatus(errAuthorizationDenied) { 90 | throw SMJError.authorizationDenied // "The system denied the authorization request" 91 | } else if status == OSStatus(errAuthorizationCanceled) { 92 | throw SMJError.authorizationCanceled // "The user canceled the authorization request" 93 | } else if status == OSStatus(errAuthorizationInteractionNotAllowed) { 94 | throw SMJError.authorizationInteractionNotAllowed // "Not allowed to prompt the user for authorization" 95 | } else { 96 | throw SMJError.authorizationFailed(status) // String(format: "Unknown failure when calling AuthorizationCreate (OSStatus %d)", status) 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /Sources/SMJobKit/ErrorTypes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ErrorTypes.swift 3 | // SMJobKit 4 | // 5 | // Created by Ingmar Stein on 29.03.15. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public enum SMJError: Error { 12 | 13 | // A failure when referencing a bundle that doesn't exist (or bad perms) 14 | case bundleNotFound 15 | // A failure when trying to get the SecStaticCode for a bundle, but it is unsigned 16 | case unsignedBundle 17 | // Unknown failure when calling SecStaticCodeCreateWithPath 18 | case badBundleSecurity(OSStatus) 19 | // Unknown failure when calling SecCodeCopySigningInformation for a bundle 20 | case badBundleCodeSigningDictionary 21 | 22 | // Failure when calling SMJobBless 23 | case unableToBless(Error) 24 | 25 | // Authorization was denied by the system when asking a user for authorization 26 | case authorizationDenied 27 | // The user canceled a prompt for authorization 28 | case authorizationCanceled 29 | // Unable to prompt the user (interaction disallowed) 30 | case authorizationInteractionNotAllowed 31 | // Unknown failure when prompting the user for authorization 32 | case authorizationFailed(OSStatus) 33 | 34 | public var code: Int { 35 | switch self { 36 | case .bundleNotFound: return 1000 37 | case .unsignedBundle: return 1001 38 | case .badBundleSecurity: return 1002 39 | case .badBundleCodeSigningDictionary: return 1003 40 | case .unableToBless: return 1010 41 | case .authorizationDenied: return 1020 42 | case .authorizationCanceled: return 1021 43 | case .authorizationInteractionNotAllowed: return 1022 44 | case .authorizationFailed: return 1023 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Tests/SMJobKitTests/ClientTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClientTests.swift 3 | // SMJobKit 4 | // 5 | // Created by Ingmar Stein on 29.03.15. 6 | // 7 | // 8 | 9 | import Cocoa 10 | import XCTest 11 | @testable import SMJobKit 12 | 13 | class ClientTests: XCTestCase { 14 | 15 | func testBundledVersion() { 16 | XCTAssert(TestClient.bundledVersion! == "0.01", "Missing/wrong version") 17 | XCTAssert(MissingClient.bundledVersion == nil, "Missing client should return nil") 18 | } 19 | 20 | func testForProblems() { 21 | XCTAssert(TestClient.checkForProblems().isEmpty, "TestService should not have problems") 22 | 23 | let errors = MissingClient.checkForProblems() 24 | XCTAssertEqual(errors.count, 1, "MissingService should have one error") 25 | if let error = errors.first! as? SMJError { 26 | switch error { 27 | case .bundleNotFound: 28 | break 29 | default: 30 | XCTAssert(false, "Missing service should be missing") 31 | } 32 | } else { 33 | XCTAssert(false, "Missing service should be missing") 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Tests/SMJobKitTests/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 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/SMJobKitTests/MissingClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMJMissingClient.swift 3 | // SMJobKit 4 | // 5 | // Created by Ingmar Stein on 29.03.15. 6 | // 7 | // 8 | 9 | import SMJobKit 10 | 11 | class MissingClient: Client { 12 | 13 | override class var serviceIdentifier: String { 14 | return "net.nevir.SMJobKitTests.MissingService" 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Tests/SMJobKitTests/TestClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMJTestClient.swift 3 | // SMJobKit 4 | // 5 | // Created by Ingmar Stein on 29.03.15. 6 | // 7 | // 8 | 9 | import SMJobKit 10 | 11 | class TestClient: Client { 12 | override class var serviceIdentifier: String { 13 | return "net.nevir.SMJobKitTests.TestService" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/TestService/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | net.nevir.SMJobKitTests.TestService 7 | CFBundleInfoDictionaryVersion 8 | 6.0 9 | CFBundleName 10 | TestService 11 | CFBundleVersion 12 | 0.01 13 | SMAuthorizedClients 14 | 15 | identifier net.nevir.SMJobKit and certificate leaf[subject.CN] = "${CODE_SIGN_IDENTITY}" 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Tests/TestService/Launchd.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | net.nevir.SMJobKitTests.TestService 7 | MachServices 8 | 9 | net.nevir.SMJobKitTests.TestService 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Tests/TestService/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TestService 4 | // 5 | // Created by Ian MacLeod on 7/9/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | int main(int argc, const char *argv[]) 10 | { 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /Xcode Templates/Application/SMJobKit-Based Application.xctemplate/README-SMJobKit.md: -------------------------------------------------------------------------------- 1 | Getting Started With Your SMJobKit-based Application 2 | ==================================================== 3 | 4 | There are a few manual steps that you need to perform before you can build your application: 5 | 6 | 1. Add your service's binary (product) to the Copy Files build phase of your application (the phase 7 | for `Contents/Library/LaunchServices`). 8 | 9 | 2. Set up your application's target to link with `SMJobKit.framework`. 10 | 11 | Xcode templates can do a lot, but not everything! Plus, they're not really documented. If you 12 | know how to accomplish any of the above steps via template configuration, let me know, please :) 13 | -------------------------------------------------------------------------------- /Xcode Templates/Application/SMJobKit-Based Application.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kind 6 | Xcode.Xcode3.ProjectTemplateUnitKind 7 | Identifier 8 | net.nevir.SMJobKit.Application 9 | InjectionTargets 10 | 11 | com.apple.dt.unit.cocoaApplication 12 | 13 | Options 14 | 15 | 16 | Identifier 17 | includeSMJobKitService 18 | Name 19 | Include SMJobKit Service 20 | SortOrder 21 | 1 22 | Description 23 | Whether the application should also bundle a SMJobKit-based system service. 24 | Type 25 | checkbox 26 | Default 27 | false 28 | Units 29 | 30 | true 31 | 32 | 33 | Components 34 | 35 | 36 | Identifier 37 | net.nevir.SMJobKit.Service 38 | Name 39 | ___VARIABLE_smjServiceName:RFC1034Identifier___ 40 | Dependents 41 | 42 | 0 43 | 44 | 45 | 46 | Targets 47 | 48 | 49 | SharedSettings 50 | 51 | CODE_SIGN_IDENTITY 52 | Mac Developer 53 | 54 | BuildPhases 55 | 56 | 57 | Class 58 | ShellScript 59 | ShellPath 60 | /usr/bin/env ruby 61 | ShellScript 62 | # Postprocessing for your info.plist. Primarily so that we can inject your full dev certificate name. 63 | 64 | require 'cgi' 65 | require 'fileutils' 66 | 67 | missing_keys = ['BUILD_DIR', 'CODE_SIGN_IDENTITY', 'TARGET_BUILD_DIR', 'INFOPLIST_PATH'] - ENV.keys 68 | raise "Missing required ENV values: #{missing_keys.inspect}" if missing_keys.size > 0 69 | 70 | files_to_postprocess = [ENV['INFOPLIST_PATH']] 71 | 72 | 73 | # FULL_CODE_SIGN_IDENTITY 74 | # ----------------------- 75 | dummy_path = "#{ENV['BUILD_DIR']}/SMJobKitCodeSigningDummy" 76 | 77 | identity = ENV['CODE_SIGN_IDENTITY'] 78 | # If you use the generic code signing identity, chances are that it'll conflict. 79 | identity = "#{identity}:" if identity.end_with? ' Developer' 80 | 81 | # We can't seem to get direct access to the code signing certificate that Xcode has 82 | # selected at this point :( 83 | `touch #{dummy_path}` 84 | `codesign --force --sign "#{identity}" "#{dummy_path}"` 85 | result = `codesign --display --verbose --verbose "#{dummy_path}" 2>&1` 86 | `rm #{dummy_path}` 87 | 88 | ENV['FULL_CODE_SIGN_IDENTITY'] = result[/Authority\=(.*#{Regexp.escape(identity)}.*)/, 1] 89 | 90 | 91 | # Actual Preprocessing 92 | # -------------------- 93 | 94 | files_to_postprocess.each do |path| 95 | target_path = File.join(ENV['TARGET_BUILD_DIR'], path) 96 | 97 | input = open(target_path).read 98 | open(target_path, 'w') do |output| 99 | # Specify macros via [[[VAR_NAME]]] to avoid clashes w/ regular plist preprocessing. 100 | output.write input.gsub(/\[\[\[([A-Z_]+)\]\]\]/) { CGI.escapeHTML(ENV[$1]) } 101 | end 102 | end 103 | 104 | 105 | Class 106 | CopyFiles 107 | DstPath 108 | Contents/Library/LaunchServices 109 | DstSubfolderSpec 110 | 1 111 | 112 | 113 | 114 | 115 | Nodes 116 | 117 | README-SMJobKit.md 118 | Info.plist:SMPrivilegedExecutables 119 | ___VARIABLE_smjServiceName:RFC1034Identifier___.swift 120 | AppDelegate.swift:implementation:methods:applicationDidFinishLaunching:installSMJServices 121 | AppDelegate.swift:implementation:methods:installServices 122 | AppDelegate.swift:implementation:methods:installServices:___VARIABLE_smjServiceName:RFC1034Identifier___ 123 | 124 | Definitions 125 | 126 | README-SMJobKit.md 127 | 128 | Path 129 | README-SMJobKit.md 130 | 131 | Info.plist:SMPrivilegedExecutables 132 | 133 | <key>SMPrivilegedExecutables</key> 134 | <dict> 135 | <key>___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___.[[[PROJECT_NAME]]].___VARIABLE_smjServiceName:RFC1034Identifier___</key> 136 | <string>identifier ___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___.[[[PROJECT_NAME]]].___VARIABLE_smjServiceName:RFC1034Identifier___ and certificate leaf[subject.CN] = "[[[FULL_CODE_SIGN_IDENTITY]]]"</string> 137 | </dict> 138 | 139 | ___VARIABLE_smjServiceName:RFC1034Identifier___.swift 140 | 141 | Path 142 | ___VARIABLE_smjServiceName:RFC1034Identifier___.swift 143 | Group 144 | Service Clients 145 | 146 | AppDelegate.swift:implementation:methods:installServices 147 | 148 | Beginning 149 | private func installServices() { 150 | End 151 | } 152 | Indent 153 | 1 154 | 155 | AppDelegate.swift:implementation:methods:installServices:___VARIABLE_smjServiceName:RFC1034Identifier___ 156 | if ___VARIABLE_smjServiceName:RFC1034Identifier___.isLatestVersionInstalled { 157 | return 158 | } 159 | 160 | var error: NSError? = nil 161 | // The user will be prompted with the following: 162 | // 163 | // <Your Custom Message Here> 164 | // ___VARIABLE_productName___ is trying to install a new 165 | // helper tool. Type your password to allow this. 166 | if !___VARIABLE_smjServiceName:RFC1034Identifier___.installWithPrompt("<Your Custom Message Here>", error:&error) { 167 | // Let the user know something went wrong! 168 | } 169 | AppDelegate.swift:implementation:methods:applicationDidFinishLaunching:installSMJServices 170 | installServices() 171 | 172 | 173 | 174 | 175 | 176 | 177 | Identifier 178 | smjServiceName 179 | Required 180 | 181 | Name 182 | Service Name 183 | SortOrder 184 | 2 185 | Description 186 | The SMJobKit service's base name 187 | EmptyReplacement 188 | ServiceName 189 | Type 190 | text 191 | RequiredOptions 192 | 193 | includeSMJobKitService 194 | true 195 | 196 | 197 | 198 | Identifier 199 | smjServiceBundleIdentifier 200 | Name 201 | Service Identifier 202 | SortOrder 203 | 2 204 | NotPersisted 205 | 206 | Description 207 | Your new service's bundle and launchd identifier 208 | Default 209 | ___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___.___VARIABLE_productName:RFC1034Identifier___.___VARIABLE_smjServiceName:RFC1034Identifier___ 210 | Type 211 | static 212 | RequiredOptions 213 | 214 | includeSMJobKitService 215 | true 216 | 217 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /Xcode Templates/Application/SMJobKit-Based Application.xctemplate/___VARIABLE_smjServiceName:RFC1034Identifier___.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PACKAGENAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | //___COPYRIGHT___ 7 | // 8 | 9 | import SMJobKit 10 | 11 | class ___FILEBASENAMEASIDENTIFIER___: Client { 12 | 13 | override class var serviceIdentifier: String { 14 | return "___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___.___VARIABLE_productName___.___VARIABLE_smjServiceName:RFC1034Identifier___" 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Xcode Templates/Framework & Library/SMJobKit Service.xctemplate/TemplateIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IngmarStein/SMJobKit/4ed936712e6994a037581d33e1afbadda15e3394/Xcode Templates/Framework & Library/SMJobKit Service.xctemplate/TemplateIcon.icns -------------------------------------------------------------------------------- /Xcode Templates/Framework & Library/SMJobKit Service.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kind 6 | Xcode.Xcode3.ProjectTemplateUnitKind 7 | Identifier 8 | net.nevir.SMJobKit.Service 9 | Concrete 10 | 11 | Description 12 | This template builds a SMJobKit Service 13 | SortOrder 14 | 3 15 | Ancestors 16 | 17 | com.apple.dt.unit.macReferenceCounting 18 | 19 | Options 20 | 21 | 22 | Identifier 23 | productName 24 | Required 25 | 26 | Name 27 | Service Name 28 | NotPersisted 29 | 30 | Description 31 | Your new SMJobKit service's name 32 | EmptyReplacement 33 | ServiceName 34 | Type 35 | text 36 | 37 | 38 | Identifier 39 | bundleIdentifierPrefix 40 | Required 41 | 42 | Name 43 | Company Identifier 44 | Description 45 | Your company's bundle identifier prefix 46 | EmptyReplacement 47 | com.yourcompany 48 | Type 49 | text 50 | 51 | 52 | Identifier 53 | bundleIdentifier 54 | Name 55 | Bundle Identifier 56 | NotPersisted 57 | 58 | Description 59 | Your new service's bundle and launchd identifier 60 | Default 61 | ___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___.<Project>.___VARIABLE_productName___ 62 | Type 63 | static 64 | 65 | 66 | Project 67 | 68 | SharedSettings 69 | 70 | CODE_SIGN_IDENTITY 71 | Mac Developer 72 | GCC_C_LANGUAGE_STANDARD 73 | gnu99 74 | GCC_WARN_ABOUT_RETURN_TYPE 75 | YES 76 | GCC_WARN_UNINITIALIZED_AUTOS 77 | YES 78 | GCC_WARN_UNUSED_VARIABLE 79 | YES 80 | ALWAYS_SEARCH_USER_PATHS 81 | NO 82 | 83 | Configurations 84 | 85 | Debug 86 | 87 | GCC_OPTIMIZATION_LEVEL 88 | 0 89 | GCC_PREPROCESSOR_DEFINITIONS 90 | DEBUG=1 $(inherited) 91 | COPY_PHASE_STRIP 92 | NO 93 | GCC_DYNAMIC_NO_PIC 94 | NO 95 | 96 | Release 97 | 98 | COPY_PHASE_STRIP 99 | YES 100 | 101 | 102 | 103 | Targets 104 | 105 | 106 | ProductType 107 | com.apple.product-type.tool 108 | SharedSettings 109 | 110 | PRODUCT_NAME 111 | ___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___.$(PROJECT_NAME).$(TARGET_NAME) 112 | PARENT_APPLICATION_IDENTIFIER 113 | ___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___.$(PROJECT_NAME) 114 | SMJ_PREPROCESS_DIR 115 | $(BUILD_DIR)/Preprocessed 116 | SMJ_PREPROCESS_FILES 117 | ___PACKAGENAME___/___PACKAGENAMEASIDENTIFIER___-Info.plist, ___PACKAGENAME___/___PACKAGENAMEASIDENTIFIER___-Launchd.plist 118 | OTHER_LDFLAGS 119 | -sectcreate __TEXT __info_plist "$(SMJ_PREPROCESS_DIR)/___PACKAGENAME___/___PACKAGENAMEASIDENTIFIER___-Info.plist" -sectcreate __TEXT __launchd_plist "$(SMJ_PREPROCESS_DIR)/___PACKAGENAME___/___PACKAGENAMEASIDENTIFIER___-Launchd.plist" 120 | 121 | BuildPhases 122 | 123 | 124 | Class 125 | ShellScript 126 | ShellPath 127 | /usr/bin/env ruby 128 | ShellScript 129 | # Generic preprocessing for ${ENV_VAR} with output to the build dir. 130 | 131 | require 'cgi' 132 | require 'fileutils' 133 | 134 | missing_keys = ['BUILD_DIR', 'CODE_SIGN_IDENTITY', 'SMJ_PREPROCESS_FILES', 'SMJ_PREPROCESS_DIR'] - ENV.keys 135 | raise "Missing required ENV values: #{missing_keys.inspect}" if missing_keys.size > 0 136 | 137 | # SMJ_PREPROCESS_FILES is a comma-separated list of *relative* file paths to preprocess 138 | # and spit out into the SMJ_PREPROCESS_DIR (w/ the same relative paths as given) 139 | files_to_preprocess = ENV['SMJ_PREPROCESS_FILES'].split(',').map(&:strip) 140 | 141 | 142 | # Environment Cleanup 143 | # ------------------- 144 | dummy_path = "#{ENV['BUILD_DIR']}/SMJobKitCodeSigningDummy" 145 | 146 | identity = ENV['CODE_SIGN_IDENTITY'] 147 | # If you use the generic code signing identity, chances are that it'll conflict. 148 | identity = "#{identity}:" if identity.end_with? ' Developer' 149 | 150 | # We can't seem to get direct access to the code signing certificate that Xcode has 151 | # selected at this point :( 152 | `touch #{dummy_path}` 153 | `codesign --force --sign "#{identity}" "#{dummy_path}"` 154 | result = `codesign --display --verbose --verbose "#{dummy_path}" 2>&1` 155 | `rm #{dummy_path}` 156 | 157 | ENV['FULL_CODE_SIGN_IDENTITY'] = result[/Authority\=(.*#{Regexp.escape(identity)}.*)/, 1] 158 | 159 | 160 | # Actual Preprocessing 161 | # -------------------- 162 | 163 | files_to_preprocess.each do |path| 164 | target_path = File.join(ENV['SMJ_PREPROCESS_DIR'], path) 165 | FileUtils.mkpath File.dirname(target_path) 166 | 167 | open(path) do |input| 168 | open(target_path, 'w') do |output| 169 | # Specify macros via ${VAR_NAME} in the preprocessed file. Same as regular 170 | # Info.plist preprocessing. 171 | output.write input.read.gsub(/\$\{([A-Z_]+)\}/) { CGI.escapeHTML(ENV[$1]) } 172 | end 173 | puts target_path 174 | end 175 | end 176 | 177 | 178 | Class 179 | Sources 180 | 181 | 182 | Class 183 | Frameworks 184 | 185 | 186 | Frameworks 187 | 188 | Foundation 189 | 190 | 191 | 192 | Nodes 193 | 194 | main.m 195 | ___PACKAGENAMEASIDENTIFIER___-Info.plist 196 | ___PACKAGENAMEASIDENTIFIER___-Launchd.plist 197 | 198 | Definitions 199 | 200 | main.m 201 | 202 | Path 203 | main.m 204 | 205 | ___PACKAGENAMEASIDENTIFIER___-Info.plist 206 | 207 | Path 208 | ___PACKAGENAMEASIDENTIFIER___-Info.plist 209 | 210 | ___PACKAGENAMEASIDENTIFIER___-Launchd.plist 211 | 212 | Path 213 | ___PACKAGENAMEASIDENTIFIER___-Launchd.plist 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /Xcode Templates/Framework & Library/SMJobKit Service.xctemplate/___PACKAGENAMEASIDENTIFIER___-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | ${PRODUCT_NAME} 7 | CFBundleInfoDictionaryVersion 8 | 6.0 9 | CFBundleName 10 | ___PACKAGENAMEASIDENTIFIER___ 11 | CFBundleVersion 12 | 0.01 13 | SMAuthorizedClients 14 | 15 | identifier ${PARENT_APPLICATION_IDENTIFIER} and certificate leaf[subject.CN] = "${FULL_CODE_SIGN_IDENTITY}" 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Xcode Templates/Framework & Library/SMJobKit Service.xctemplate/___PACKAGENAMEASIDENTIFIER___-Launchd.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | ${PRODUCT_NAME} 7 | MachServices 8 | 9 | ${PRODUCT_NAME} 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Xcode Templates/Framework & Library/SMJobKit Service.xctemplate/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PACKAGENAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | // Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. 7 | // 8 | 9 | int main(int argc, const char *argv[]) 10 | { 11 | return 0; 12 | } 13 | --------------------------------------------------------------------------------