├── README.md ├── Shared (App) ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── LargeIcon.imageset │ │ └── Contents.json ├── Base.lproj │ └── Main.html ├── KeychainHelper.swift ├── Resources │ ├── Icon.png │ ├── Script.js │ ├── Style.css │ └── gist-icon.png └── ViewController.swift ├── Shared (Extension) ├── Resources │ ├── _locales │ │ └── en │ │ │ └── messages.json │ ├── background.js │ ├── content.js │ ├── images │ │ ├── gist-icon-128.png │ │ ├── gist-icon-256.png │ │ ├── gist-icon-48.png │ │ ├── gist-icon-512.png │ │ ├── gist-icon-96.png │ │ ├── gist-toolbar-icon-16.png │ │ ├── gist-toolbar-icon-19.png │ │ ├── gist-toolbar-icon-32.png │ │ ├── gist-toolbar-icon-38.png │ │ ├── gist-toolbar-icon-48.png │ │ └── gist-toolbar-icon-72.png │ ├── manifest.json │ ├── popup.css │ ├── popup.html │ └── popup.js └── SafariWebExtensionHandler.swift ├── gist.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── marko.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── iOS (App) ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist └── SceneDelegate.swift ├── iOS (Extension) └── Info.plist ├── macOS (App) ├── AppDelegate.swift ├── Base.lproj │ └── Main.storyboard └── gist.entitlements └── macOS (Extension) ├── Info.plist └── gist.entitlements /README.md: -------------------------------------------------------------------------------- 1 | # gist: AI Web Page Summary 2 | 3 | ## Description 4 | 5 | **gist** is a Safari Extension that uses OpenAI GPT3 AI to create a summary of the webpage you are browsing. 6 | 7 | **gist** is not "production" ready and it will not be published on the App Store. 8 | 9 | Goal of the project was to get familiar with the Apple development ecosystem, as well as learn Swift and web programming. 10 | 11 | ## Limitations 12 | 13 | - GPT3 summary can be hit or miss. 14 | - GPT3 parameters are hardcoded. 15 | - There is no consideration for the text length so prompts can fail if they exceed maximum allowed limit. 16 | - Mozilla Readability does not do a great job in extracting main text body from the web page. 17 | - Loading Mozilla Readability on the fly from Skypack can fail on certain websites due to their Content Security Policy. 18 | - Extracted webpages are not sanitized. 19 | - No error communication unless in debug mode. 20 | -------------------------------------------------------------------------------- /Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "1x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "2x", 16 | "size" : "16x16" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "1x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "2x", 26 | "size" : "32x32" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "2x", 36 | "size" : "128x128" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "1x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "2x", 46 | "size" : "256x256" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "1x", 51 | "size" : "512x512" 52 | }, 53 | { 54 | "idiom" : "mac", 55 | "scale" : "2x", 56 | "size" : "512x512" 57 | } 58 | ], 59 | "info" : { 60 | "author" : "xcode", 61 | "version" : 1 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Shared (App)/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "3x" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Shared (App)/Base.lproj/Main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | gist Icon 14 |

You can turn on gist Safari extension in Settings.

15 |

You can turn on gist extension in Safari Extensions preferences.

16 |

gist extension is currently on. You can turn it off in Safari Extensions preferences.

17 |

gist extension is currently off. You can turn it on in Safari Extensions preferences.

18 |
19 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Shared (App)/KeychainHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeychainHelper.swift 3 | // gist 4 | // 5 | // Created by Marko Simic on /923/22. 6 | // 7 | 8 | import Foundation 9 | 10 | class KeychainInterface { 11 | enum KeychainError: Error { 12 | // Attempted read for an item that does not exist. 13 | case itemNotFound 14 | 15 | // Attempted save to override an existing item. 16 | // Use update instead of save to update existing items 17 | case duplicateItem 18 | 19 | // A read of an item in any format other than Data 20 | case invalidItemFormat 21 | 22 | // Any operation result status than errSecSuccess 23 | case unexpectedStatus(OSStatus) 24 | } 25 | } 26 | 27 | final class KeychainHelper { 28 | 29 | static func savePassword(password: Data, service: String, account: String) throws { 30 | 31 | let query: [String: AnyObject] = [ 32 | // kSecAttrService, kSecAttrAccount, and kSecClass 33 | // uniquely identify the item to save in Keychain 34 | kSecAttrService as String: service as AnyObject, 35 | kSecAttrAccount as String: account as AnyObject, 36 | kSecClass as String: kSecClassGenericPassword, 37 | 38 | // kSecValueData is the item value to save 39 | kSecValueData as String: password as AnyObject 40 | ] 41 | 42 | // SecItemAdd attempts to add the item identified by 43 | // the query to keychain 44 | let status = SecItemAdd( 45 | query as CFDictionary, 46 | nil 47 | ) 48 | 49 | // errSecDuplicateItem is a special case where the 50 | // item identified by the query already exists. Throw 51 | // duplicateItem so the client can determine whether 52 | // or not to handle this as an error 53 | if status == errSecDuplicateItem { 54 | throw KeychainInterface.KeychainError.duplicateItem 55 | } 56 | 57 | // Any status other than errSecSuccess indicates the 58 | // save operation failed. 59 | guard status == errSecSuccess else { 60 | throw KeychainInterface.KeychainError.unexpectedStatus(status) 61 | } 62 | } 63 | 64 | static func updatePassword(password: Data, service: String, account: String) throws { 65 | let query: [String: AnyObject] = [ 66 | // kSecAttrService, kSecAttrAccount, and kSecClass 67 | // uniquely identify the item to update in Keychain 68 | kSecAttrService as String: service as AnyObject, 69 | kSecAttrAccount as String: account as AnyObject, 70 | kSecClass as String: kSecClassGenericPassword 71 | ] 72 | 73 | // attributes is passed to SecItemUpdate with 74 | // kSecValueData as the updated item value 75 | let attributes: [String: AnyObject] = [ 76 | kSecValueData as String: password as AnyObject 77 | ] 78 | 79 | // SecItemUpdate attempts to update the item identified 80 | // by query, overriding the previous value 81 | let status = SecItemUpdate( 82 | query as CFDictionary, 83 | attributes as CFDictionary 84 | ) 85 | 86 | // errSecItemNotFound is a special status indicating the 87 | // item to update does not exist. Throw itemNotFound so 88 | // the client can determine whether or not to handle 89 | // this as an error 90 | guard status != errSecItemNotFound else { 91 | throw KeychainInterface.KeychainError.itemNotFound 92 | } 93 | 94 | // Any status other than errSecSuccess indicates the 95 | // update operation failed. 96 | guard status == errSecSuccess else { 97 | throw KeychainInterface.KeychainError.unexpectedStatus(status) 98 | } 99 | } 100 | 101 | static func readPassword(service: String, account: String) throws -> Data { 102 | let query: [String: AnyObject] = [ 103 | // kSecAttrService, kSecAttrAccount, and kSecClass 104 | // uniquely identify the item to read in Keychain 105 | kSecAttrService as String: service as AnyObject, 106 | kSecAttrAccount as String: account as AnyObject, 107 | kSecClass as String: kSecClassGenericPassword, 108 | 109 | // kSecMatchLimitOne indicates keychain should read 110 | // only the most recent item matching this query 111 | kSecMatchLimit as String: kSecMatchLimitOne, 112 | 113 | // kSecReturnData is set to kCFBooleanTrue in order 114 | // to retrieve the data for the item 115 | kSecReturnData as String: kCFBooleanTrue 116 | ] 117 | 118 | // SecItemCopyMatching will attempt to copy the item 119 | // identified by query to the reference itemCopy 120 | var itemCopy: AnyObject? 121 | let status = SecItemCopyMatching( 122 | query as CFDictionary, 123 | &itemCopy 124 | ) 125 | 126 | // errSecItemNotFound is a special status indicating the 127 | // read item does not exist. Throw itemNotFound so the 128 | // client can determine whether or not to handle 129 | // this case 130 | guard status != errSecItemNotFound else { 131 | throw KeychainInterface.KeychainError.itemNotFound 132 | } 133 | 134 | // Any status other than errSecSuccess indicates the 135 | // read operation failed. 136 | guard status == errSecSuccess else { 137 | throw KeychainInterface.KeychainError.unexpectedStatus(status) 138 | } 139 | 140 | // This implementation of KeychainInterface requires all 141 | // items to be saved and read as Data. Otherwise, 142 | // invalidItemFormat is thrown 143 | guard let password = itemCopy as? Data else { 144 | throw KeychainInterface.KeychainError.invalidItemFormat 145 | } 146 | 147 | return password 148 | } 149 | 150 | static func deletePassword(service: String, account: String) throws { 151 | let query: [String: AnyObject] = [ 152 | // kSecAttrService, kSecAttrAccount, and kSecClass 153 | // uniquely identify the item to delete in Keychain 154 | kSecAttrService as String: service as AnyObject, 155 | kSecAttrAccount as String: account as AnyObject, 156 | kSecClass as String: kSecClassGenericPassword 157 | ] 158 | 159 | // SecItemDelete attempts to perform a delete operation 160 | // for the item identified by query. The status indicates 161 | // if the operation succeeded or failed. 162 | let status = SecItemDelete(query as CFDictionary) 163 | 164 | // Any status other than errSecSuccess indicates the 165 | // delete operation failed. 166 | guard status == errSecSuccess else { 167 | throw KeychainInterface.KeychainError.unexpectedStatus(status) 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /Shared (App)/Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (App)/Resources/Icon.png -------------------------------------------------------------------------------- /Shared (App)/Resources/Script.js: -------------------------------------------------------------------------------- 1 | function show(platform, enabled, useSettingsInsteadOfPreferences) { 2 | document.body.classList.add(`platform-${platform}`); 3 | 4 | if (useSettingsInsteadOfPreferences) { 5 | document.getElementsByClassName('platform-mac state-on')[0].innerText = "gist’s extension is currently on. You can turn it off in the Extensions section of Safari Settings."; 6 | document.getElementsByClassName('platform-mac state-off')[0].innerText = "gist’s extension is currently off. You can turn it on in the Extensions section of Safari Settings."; 7 | document.getElementsByClassName('platform-mac state-unknown')[0].innerText = "You can turn on gist’s extension in the Extensions section of Safari Settings."; 8 | document.getElementsByClassName('platform-mac open-preferences')[0].innerText = "Quit and Open Safari Settings…"; 9 | } 10 | 11 | if (typeof enabled === "boolean") { 12 | document.body.classList.toggle(`state-on`, enabled); 13 | document.body.classList.toggle(`state-off`, !enabled); 14 | } else { 15 | document.body.classList.remove(`state-on`); 16 | document.body.classList.remove(`state-off`); 17 | } 18 | } 19 | 20 | function openPreferences() { 21 | webkit.messageHandlers.controller.postMessage({ command: "open-preferences" }); 22 | } 23 | 24 | function saveApiKey(e) { 25 | e.preventDefault(); 26 | let formData = new FormData(e.target); 27 | let formProps = Object.fromEntries(formData); 28 | formProps["command"] = "api-key" 29 | webkit.messageHandlers.controller.postMessage(formProps); 30 | } 31 | 32 | function retrieveApiKey() { 33 | webkit.messageHandlers.controller.postMessage({ command: "retrieve-api-key" }); 34 | } 35 | 36 | document.querySelector("button.open-preferences").addEventListener("click", openPreferences); 37 | document.querySelector("form.save-api-key").addEventListener("submit", saveApiKey); 38 | document.querySelector("button.retrieve-api-key").addEventListener("click", retrieveApiKey); 39 | 40 | -------------------------------------------------------------------------------- /Shared (App)/Resources/Style.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-user-select: none; 3 | -webkit-user-drag: none; 4 | cursor: default; 5 | } 6 | 7 | :root { 8 | color-scheme: light dark; 9 | 10 | --spacing: 20px; 11 | } 12 | 13 | html { 14 | height: 100%; 15 | } 16 | 17 | body { 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | flex-direction: column; 22 | 23 | gap: var(--spacing); 24 | margin: 0 calc(var(--spacing) * 2); 25 | height: 100%; 26 | 27 | font: -apple-system-short-body; 28 | text-align: center; 29 | } 30 | 31 | body:not(.platform-mac, .platform-ios) :is(.platform-mac, .platform-ios) { 32 | display: none; 33 | } 34 | 35 | body.platform-ios .platform-mac { 36 | display: none; 37 | } 38 | 39 | body.platform-mac .platform-ios { 40 | display: none; 41 | } 42 | 43 | body.platform-ios .platform-mac { 44 | display: none; 45 | } 46 | 47 | body:not(.state-on, .state-off) :is(.state-on, .state-off) { 48 | display: none; 49 | } 50 | 51 | body.state-on :is(.state-off, .state-unknown) { 52 | display: none; 53 | } 54 | 55 | body.state-off :is(.state-on, .state-unknown) { 56 | display: none; 57 | } 58 | 59 | button { 60 | font-size: 1em; 61 | } 62 | 63 | input { 64 | -webkit-user-select:text; 65 | } 66 | -------------------------------------------------------------------------------- /Shared (App)/Resources/gist-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (App)/Resources/gist-icon.png -------------------------------------------------------------------------------- /Shared (App)/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Shared (App) 4 | // 5 | // Created by Marko Simic on /915/22. 6 | // 7 | 8 | import WebKit 9 | 10 | #if os(iOS) 11 | import UIKit 12 | typealias PlatformViewController = UIViewController 13 | #elseif os(macOS) 14 | import Cocoa 15 | import SafariServices 16 | typealias PlatformViewController = NSViewController 17 | #endif 18 | 19 | let extensionBundleIdentifier = "com.simicvm.gist.Extension" 20 | 21 | let account = "openai" 22 | let service = "api-token" 23 | 24 | class ViewController: PlatformViewController, WKNavigationDelegate, WKScriptMessageHandler { 25 | 26 | @IBOutlet var webView: WKWebView! 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | 31 | self.webView.navigationDelegate = self 32 | 33 | #if os(iOS) 34 | self.webView.scrollView.isScrollEnabled = false 35 | #endif 36 | 37 | self.webView.configuration.userContentController.add(self, name: "controller") 38 | 39 | self.webView.loadFileURL(Bundle.main.url(forResource: "Main", withExtension: "html")!, allowingReadAccessTo: Bundle.main.resourceURL!) 40 | } 41 | 42 | func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { 43 | #if os(iOS) 44 | webView.evaluateJavaScript("show('ios')") 45 | #elseif os(macOS) 46 | webView.evaluateJavaScript("show('mac')") 47 | 48 | SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: extensionBundleIdentifier) { (state, error) in 49 | guard let state = state, error == nil else { 50 | // Insert code to inform the user that something went wrong. 51 | return 52 | } 53 | 54 | DispatchQueue.main.async { 55 | if #available(macOS 13, *) { 56 | webView.evaluateJavaScript("show('mac', \(state.isEnabled), true)") 57 | } else { 58 | webView.evaluateJavaScript("show('mac', \(state.isEnabled), false)") 59 | } 60 | } 61 | } 62 | #endif 63 | } 64 | 65 | func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { 66 | #if os(macOS) 67 | let message = message.body as! NSDictionary 68 | if (message["command"] as! String == "open-preferences") { 69 | SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in 70 | guard error == nil else { 71 | // Insert code to inform the user that something went wrong. 72 | return 73 | } 74 | 75 | DispatchQueue.main.async { 76 | NSApplication.shared.terminate(nil) 77 | } 78 | } 79 | } else if (message["command"] as! String == "api-key") { 80 | let auth = Data((message["api-key"] as! String).utf8) 81 | DispatchQueue.global().async { 82 | do { 83 | try KeychainHelper.savePassword(password: auth, service: service, account: account) 84 | print("API key set") 85 | } catch KeychainInterface.KeychainError.duplicateItem { 86 | print("API key already exists") 87 | do { 88 | try KeychainHelper.updatePassword(password: auth, service: service, account: account) 89 | print("API key updated") 90 | } catch { 91 | print("couldn't update API key") 92 | } 93 | } catch { 94 | print("Something else went wrong!") 95 | } 96 | } 97 | } else if (message["command"] as! String == "retrieve-api-key") { 98 | do { 99 | let apiKey = try KeychainHelper.readPassword(service: service, account: account) 100 | let apiKeyString = String(data: apiKey, encoding: .utf8)! 101 | print("retrieved api key:", apiKeyString) 102 | } catch { 103 | print("error in retrieving the message") 104 | } 105 | } else { 106 | return 107 | } 108 | 109 | #endif 110 | } 111 | } 112 | 113 | -------------------------------------------------------------------------------- /Shared (Extension)/Resources/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extension_name": { 3 | "message": "gist", 4 | "description": "The display name for the extension." 5 | }, 6 | "extension_description": { 7 | "message": "This is gist. You should tell us what your extension does here.", 8 | "description": "Description of what the extension does." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Shared (Extension)/Resources/background.js: -------------------------------------------------------------------------------- 1 | browser.runtime.onMessage.addListener((request, sender, sendResponse) => { 2 | console.log("Received request: ", request); 3 | 4 | if (request.message.description = "extracted text") { 5 | browser.runtime.sendNativeMessage("application.id", {message: request.message.textContent}, function(response) { 6 | console.log("Received sendNativeMessage response"); 7 | const responseReplace = response[0].replace(/\u21B5/gi, "
").trim(); 8 | const summary = {summary: responseReplace, description: "summary"}; 9 | console.log("Sending summary to popup") 10 | browser.runtime.sendMessage({ message: summary }).then((response) => { 11 | console.log("Received response from popup: ", response); 12 | }); 13 | }); 14 | } else { 15 | console.log("Received unknown request: ", request); 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /Shared (Extension)/Resources/content.js: -------------------------------------------------------------------------------- 1 | browser.runtime.onMessage.addListener((request, sender, sendResponse) => { 2 | if (!sender.tab && request.message === "summarize") { 3 | console.log("Received request: ", request); 4 | 5 | const documentClone = document.cloneNode(true); 6 | 7 | import('https://cdn.skypack.dev/@mozilla/readability') 8 | .then((module) => { 9 | if (module.isProbablyReaderable(documentClone)) { 10 | console.log("Page is readable!"); 11 | let article = new module.Readability(documentClone).parse(); 12 | article.description = "extracted text"; 13 | browser.runtime.sendMessage({ message: article }).then((response) => { 14 | console.log("Received response: ", response); 15 | }); 16 | } else { 17 | console.log("Page is not readable!") 18 | } 19 | }) 20 | .catch((error) => { 21 | console.log(error); 22 | }); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-icon-128.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-icon-256.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-icon-48.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-icon-512.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-icon-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-icon-96.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-toolbar-icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-toolbar-icon-16.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-toolbar-icon-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-toolbar-icon-19.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-toolbar-icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-toolbar-icon-32.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-toolbar-icon-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-toolbar-icon-38.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-toolbar-icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-toolbar-icon-48.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/images/gist-toolbar-icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simicvm/gist/41585ff357f2973856c1266b635d9bf58c493174/Shared (Extension)/Resources/images/gist-toolbar-icon-72.png -------------------------------------------------------------------------------- /Shared (Extension)/Resources/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "default_locale": "en", 4 | 5 | "name": "__MSG_extension_name__", 6 | "description": "__MSG_extension_description__", 7 | "version": "1.0", 8 | 9 | "icons": { 10 | "48": "images/gist-icon-48.png", 11 | "96": "images/gist-icon-96.png", 12 | "128": "images/gist-icon-128.png", 13 | "256": "images/gist-icon-256.png", 14 | "512": "images/gist-icon-512.png" 15 | }, 16 | 17 | "background": { 18 | "service_worker": "background.js" 19 | }, 20 | 21 | "content_scripts": [{ 22 | "js": [ "content.js" ], 23 | "matches": [ "" ] 24 | }], 25 | 26 | "action": { 27 | "default_popup": "popup.html", 28 | "default_icon": { 29 | "16": "images/gist-toolbar-icon-16.png", 30 | "19": "images/gist-toolbar-icon-19.png", 31 | "32": "images/gist-toolbar-icon-32.png", 32 | "38": "images/gist-toolbar-icon-38.png", 33 | "48": "images/gist-toolbar-icon-48.png", 34 | "72": "images/gist-toolbar-icon-72.png" 35 | } 36 | }, 37 | 38 | "permissions": [ 39 | "", 40 | "nativeMessaging" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /Shared (Extension)/Resources/popup.css: -------------------------------------------------------------------------------- 1 | :root { 2 | color-scheme: light dark; 3 | } 4 | 5 | body { 6 | width: 400px; 7 | height: 300px; 8 | padding: 10px; 9 | 10 | font-family: system-ui; 11 | text-align: center; 12 | } 13 | 14 | .flex-container { 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | } 19 | 20 | button { 21 | position: relative; 22 | width: 150px; 23 | height: 150px; 24 | padding: 10px; 25 | margin: 5px 0; 26 | 27 | font-size: 1.2em; 28 | font-weight: bold; 29 | color: #fff; 30 | background-color: #0078d4; 31 | border: none; 32 | border-radius: 50%; 33 | cursor: pointer; 34 | font-size: 1.2em; 35 | font-weight: bold; 36 | } 37 | 38 | .button:active { 39 | background: #629ce8; 40 | } 41 | 42 | .button-loading::after { 43 | content: ""; 44 | position: absolute; 45 | width: 130px; 46 | height: 130px; 47 | top: 0; 48 | left: 0; 49 | right: 0; 50 | bottom: 0; 51 | margin: auto; 52 | border: 10px solid transparent; 53 | border-top-color: #ffffff; 54 | border-radius: 50%; 55 | animation: button-loading-spinner 1s ease infinite; 56 | } 57 | 58 | @keyframes button-loading-spinner { 59 | from { 60 | transform: rotate(0turn); 61 | } 62 | 63 | to { 64 | transform: rotate(1turn); 65 | } 66 | } 67 | 68 | .ai-summary-text { 69 | display: none; 70 | white-space: pre-wrap; 71 | text-align: left; 72 | } 73 | 74 | .header { 75 | width: 100%; 76 | position: relative; 77 | } 78 | 79 | .wrapper { 80 | width: 100%; 81 | position: relative; 82 | margin: 30px 0; 83 | } 84 | 85 | .logo { 86 | display: flex; 87 | } 88 | 89 | /*.logo img { 90 | width: 80px; 91 | }*/ 92 | 93 | .header-text { 94 | text-align: center; 95 | position: absolute; 96 | width: 100%; 97 | top: 50%; 98 | transform: translateY(-50%); 99 | font-size: xx-large; 100 | font-weight: bold; 101 | } 102 | 103 | @media (prefers-color-scheme: dark) { 104 | /* Dark Mode styles go here. */ 105 | } 106 | -------------------------------------------------------------------------------- /Shared (Extension)/Resources/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | 14 |
15 | gist: AI Web
Page Summary 16 |
17 |
18 |
19 |
20 | 23 |
24 | Placeholder text for the summary 25 |
26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /Shared (Extension)/Resources/popup.js: -------------------------------------------------------------------------------- 1 | const theButton = document.querySelector(".button"); 2 | const body = document.querySelector("body"); 3 | const aiSummaryText = document.querySelector(".ai-summary-text"); 4 | const headerText = document.querySelector(".header-text"); 5 | 6 | function handleResponse(message) { 7 | console.log(`Message from the background script: ${message}`); 8 | } 9 | 10 | function handleError(error) { 11 | console.log(`Error: ${error}`); 12 | } 13 | 14 | function notifyContentPage(e) { 15 | browser.tabs.query({active: true, currentWindow: true}, function(tabs) { 16 | if (tabs.length == 0) { 17 | console.log("could not send mesage to current tab"); 18 | } else { 19 | const sendingToContent = browser.tabs.sendMessage(tabs[0].id, {message: "summarize"}); 20 | sendingToContent.then(handleResponse, handleError); 21 | } 22 | }); 23 | } 24 | 25 | document.addEventListener("DOMContentLoaded", () => { 26 | document.getElementById("summarize").addEventListener("click", notifyContentPage); 27 | }); 28 | 29 | theButton.addEventListener("click", () => { 30 | theButton.classList.add("button-loading"); 31 | theButton.innerHTML = "Creating gist"; 32 | }); 33 | 34 | browser.runtime.onMessage.addListener((request, sender, sendResponse) => { 35 | if (request.message.description === "summary") { 36 | theButton.style.display = "none"; 37 | body.style.width = "600px"; 38 | headerText.innerHTML = "gist: AI Web Page Summary"; 39 | aiSummaryText.style.display = "flex"; 40 | aiSummaryText.innerHTML = request.message.summary; 41 | } else { 42 | console.log("Received unknown request: ", request); 43 | sendResponse({ farewell: "didn't manage to read it properly" }); 44 | } 45 | }); 46 | -------------------------------------------------------------------------------- /Shared (Extension)/SafariWebExtensionHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SafariWebExtensionHandler.swift 3 | // Shared (Extension) 4 | // 5 | // Created by Marko Simic on /915/22. 6 | // 7 | 8 | import SafariServices 9 | import os.log 10 | 11 | let account = "openai" 12 | let service = "api-token" 13 | 14 | struct webPageText { 15 | var text: String 16 | } 17 | 18 | struct requestBody: Codable { 19 | var model: String 20 | var temperature: Double 21 | var max_tokens: Int 22 | var prompt: String 23 | } 24 | 25 | struct choices: Codable { 26 | var text: String 27 | var index: Int 28 | var logprobs: Int? 29 | var finish_reason: String 30 | } 31 | 32 | struct completionResponse: Codable { 33 | var id: String 34 | var object: String 35 | var created: Int 36 | var model: String 37 | var choices: [choices] 38 | var usage: [String: Int] 39 | } 40 | 41 | struct errorResponse: Codable { 42 | var error: [String: String?] 43 | } 44 | 45 | extension errorResponse: CustomStringConvertible { 46 | var description: String { 47 | return "\(error)" 48 | } 49 | } 50 | 51 | func prepareRequest(prompt: String, apiKey: String) -> URLRequest { 52 | // Prepare URL 53 | let url = URL(string: "https://api.openai.com/v1/completions") 54 | guard let requestUrl = url else { fatalError() } 55 | 56 | // Prepare URL Request Object 57 | var request = URLRequest(url: requestUrl) 58 | request.httpMethod = "POST" 59 | 60 | // Set HTTP Requst Header 61 | request.setValue("application/json", forHTTPHeaderField: "Content-Type") 62 | request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") 63 | 64 | // Set HTTP Request Body 65 | let params = requestBody(model: "text-davinci-002", temperature: 0.7, max_tokens: 372, prompt: prompt) 66 | let jsonData = try? JSONEncoder().encode(params) 67 | 68 | request.httpBody = jsonData 69 | 70 | return request 71 | } 72 | 73 | func performRequest(request: URLRequest, context: NSExtensionContext) { 74 | // Perform HTTP Request 75 | let task = URLSession.shared.dataTask(with: request) { (data, response, error) in 76 | if let error = error { 77 | os_log(.error, "Error message: %{public}@", error as CVarArg) 78 | return 79 | } 80 | 81 | do { 82 | // decode json data 83 | let decoder = JSONDecoder() 84 | let object = try decoder.decode(completionResponse.self, from: data!) 85 | 86 | // handle success 87 | if #available(macOSApplicationExtension 11.0, *) { 88 | os_log(.debug, "AI answer: \(object.choices[0].text, privacy: .public)") 89 | } else { // Fallback on earlier versions 90 | os_log(.info, "Using string interpolation in os_log on unsuported macOS version!") 91 | } 92 | 93 | let response = NSExtensionItem() 94 | response.userInfo = [ SFExtensionMessageKey: [ object.choices[0].text ] ] 95 | context.completeRequest(returningItems: [response], completionHandler: nil) 96 | } catch { 97 | // handle json decoding error 98 | do { 99 | let decoder = JSONDecoder() 100 | let object = try decoder.decode(errorResponse.self, from: data!) 101 | if #available(macOSApplicationExtension 11.0, *) { 102 | os_log(.error, "Error message: \(object, privacy: .public)") 103 | } else { // Fallback on earlier versions 104 | os_log(.info, "Using string interpolation in os_log on unsuported macOS version!") 105 | } 106 | } catch { 107 | os_log(.error, "Error message: %{public}@", error as CVarArg) 108 | } 109 | } 110 | } 111 | task.resume() 112 | } 113 | 114 | let SFExtensionMessageKey = "message" 115 | 116 | class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { 117 | 118 | func beginRequest(with context: NSExtensionContext) { 119 | let item = context.inputItems[0] as! NSExtensionItem 120 | let message = item.userInfo?[SFExtensionMessageKey] 121 | let messageDict = message as! NSDictionary 122 | var messageContent = messageDict.value(forKey: "message") as! String 123 | messageContent = "Summarize the following text in less than 10 bulletpoints: " + "\"" + messageContent + "\"" 124 | if #available(macOSApplicationExtension 11.0, *) { 125 | os_log(.debug, "This is the text from web: \(messageContent, privacy: .public)") 126 | } else { 127 | os_log(.info, "Using string interpolation in os_log on unsuported macOS version!") 128 | } 129 | os_log(.debug, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg) 130 | 131 | do { 132 | let apiKey = try KeychainHelper.readPassword(service: service, account: account) 133 | let apiKeyString = String(data: apiKey, encoding: .utf8)! 134 | 135 | let request = prepareRequest(prompt: messageContent, apiKey: apiKeyString) 136 | //let request = prepareRequest(prompt: "Say 'This is a test'", apiKey: apiKeyString) 137 | performRequest(request: request, context: context) 138 | } catch { 139 | os_log(.error, "Something went wrong") 140 | } 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /gist.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | AD15920228DDD53400506584 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD15920128DDD53400506584 /* KeychainHelper.swift */; }; 11 | AD15920328DDD53400506584 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD15920128DDD53400506584 /* KeychainHelper.swift */; }; 12 | AD15920428DEC78D00506584 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD15920128DDD53400506584 /* KeychainHelper.swift */; }; 13 | AD15920528DEC78E00506584 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD15920128DDD53400506584 /* KeychainHelper.swift */; }; 14 | AD15921528E97E8C00506584 /* gist-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = AD15921428E97E8C00506584 /* gist-icon.png */; }; 15 | AD15921628E97E8C00506584 /* gist-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = AD15921428E97E8C00506584 /* gist-icon.png */; }; 16 | ADB408DE28D2ED07002AD44D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB408DD28D2ED07002AD44D /* AppDelegate.swift */; }; 17 | ADB408E028D2ED07002AD44D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB408DF28D2ED07002AD44D /* SceneDelegate.swift */; }; 18 | ADB408E328D2ED07002AD44D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ADB408E128D2ED07002AD44D /* LaunchScreen.storyboard */; }; 19 | ADB408E628D2ED07002AD44D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ADB408E428D2ED07002AD44D /* Main.storyboard */; }; 20 | ADB408EF28D2ED07002AD44D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB408EE28D2ED07002AD44D /* AppDelegate.swift */; }; 21 | ADB408F228D2ED07002AD44D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ADB408F028D2ED07002AD44D /* Main.storyboard */; }; 22 | ADB408F928D2ED07002AD44D /* gist Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = ADB408F828D2ED07002AD44D /* gist Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 23 | ADB4090328D2ED07002AD44D /* gist Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = ADB4090228D2ED07002AD44D /* gist Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 24 | ADB4090928D2ED07002AD44D /* Main.html in Resources */ = {isa = PBXBuildFile; fileRef = ADB408C428D2ED06002AD44D /* Main.html */; }; 25 | ADB4090A28D2ED07002AD44D /* Main.html in Resources */ = {isa = PBXBuildFile; fileRef = ADB408C428D2ED06002AD44D /* Main.html */; }; 26 | ADB4090D28D2ED07002AD44D /* Style.css in Resources */ = {isa = PBXBuildFile; fileRef = ADB408C728D2ED06002AD44D /* Style.css */; }; 27 | ADB4090E28D2ED07002AD44D /* Style.css in Resources */ = {isa = PBXBuildFile; fileRef = ADB408C728D2ED06002AD44D /* Style.css */; }; 28 | ADB4090F28D2ED07002AD44D /* Script.js in Resources */ = {isa = PBXBuildFile; fileRef = ADB408C828D2ED06002AD44D /* Script.js */; }; 29 | ADB4091028D2ED07002AD44D /* Script.js in Resources */ = {isa = PBXBuildFile; fileRef = ADB408C828D2ED06002AD44D /* Script.js */; }; 30 | ADB4091128D2ED07002AD44D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB408C928D2ED06002AD44D /* ViewController.swift */; }; 31 | ADB4091228D2ED07002AD44D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB408C928D2ED06002AD44D /* ViewController.swift */; }; 32 | ADB4091328D2ED07002AD44D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ADB408CA28D2ED07002AD44D /* Assets.xcassets */; }; 33 | ADB4091428D2ED07002AD44D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ADB408CA28D2ED07002AD44D /* Assets.xcassets */; }; 34 | ADB4091528D2ED07002AD44D /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB408CC28D2ED07002AD44D /* SafariWebExtensionHandler.swift */; }; 35 | ADB4091628D2ED07002AD44D /* SafariWebExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB408CC28D2ED07002AD44D /* SafariWebExtensionHandler.swift */; }; 36 | ADB4091728D2ED07002AD44D /* _locales in Resources */ = {isa = PBXBuildFile; fileRef = ADB408CE28D2ED07002AD44D /* _locales */; }; 37 | ADB4091828D2ED07002AD44D /* _locales in Resources */ = {isa = PBXBuildFile; fileRef = ADB408CE28D2ED07002AD44D /* _locales */; }; 38 | ADB4091928D2ED07002AD44D /* images in Resources */ = {isa = PBXBuildFile; fileRef = ADB408CF28D2ED07002AD44D /* images */; }; 39 | ADB4091A28D2ED07002AD44D /* images in Resources */ = {isa = PBXBuildFile; fileRef = ADB408CF28D2ED07002AD44D /* images */; }; 40 | ADB4091B28D2ED07002AD44D /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D028D2ED07002AD44D /* manifest.json */; }; 41 | ADB4091C28D2ED07002AD44D /* manifest.json in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D028D2ED07002AD44D /* manifest.json */; }; 42 | ADB4091D28D2ED07002AD44D /* background.js in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D128D2ED07002AD44D /* background.js */; }; 43 | ADB4091E28D2ED07002AD44D /* background.js in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D128D2ED07002AD44D /* background.js */; }; 44 | ADB4091F28D2ED07002AD44D /* content.js in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D228D2ED07002AD44D /* content.js */; }; 45 | ADB4092028D2ED07002AD44D /* content.js in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D228D2ED07002AD44D /* content.js */; }; 46 | ADB4092128D2ED07002AD44D /* popup.html in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D328D2ED07002AD44D /* popup.html */; }; 47 | ADB4092228D2ED07002AD44D /* popup.html in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D328D2ED07002AD44D /* popup.html */; }; 48 | ADB4092328D2ED07002AD44D /* popup.css in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D428D2ED07002AD44D /* popup.css */; }; 49 | ADB4092428D2ED07002AD44D /* popup.css in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D428D2ED07002AD44D /* popup.css */; }; 50 | ADB4092528D2ED07002AD44D /* popup.js in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D528D2ED07002AD44D /* popup.js */; }; 51 | ADB4092628D2ED07002AD44D /* popup.js in Resources */ = {isa = PBXBuildFile; fileRef = ADB408D528D2ED07002AD44D /* popup.js */; }; 52 | /* End PBXBuildFile section */ 53 | 54 | /* Begin PBXContainerItemProxy section */ 55 | ADB408FA28D2ED07002AD44D /* PBXContainerItemProxy */ = { 56 | isa = PBXContainerItemProxy; 57 | containerPortal = ADB408BE28D2ED06002AD44D /* Project object */; 58 | proxyType = 1; 59 | remoteGlobalIDString = ADB408F728D2ED07002AD44D; 60 | remoteInfo = "gist Extension (iOS)"; 61 | }; 62 | ADB4090428D2ED07002AD44D /* PBXContainerItemProxy */ = { 63 | isa = PBXContainerItemProxy; 64 | containerPortal = ADB408BE28D2ED06002AD44D /* Project object */; 65 | proxyType = 1; 66 | remoteGlobalIDString = ADB4090128D2ED07002AD44D; 67 | remoteInfo = "gist Extension (macOS)"; 68 | }; 69 | /* End PBXContainerItemProxy section */ 70 | 71 | /* Begin PBXCopyFilesBuildPhase section */ 72 | ADB4092C28D2ED07002AD44D /* Embed Foundation Extensions */ = { 73 | isa = PBXCopyFilesBuildPhase; 74 | buildActionMask = 2147483647; 75 | dstPath = ""; 76 | dstSubfolderSpec = 13; 77 | files = ( 78 | ADB408F928D2ED07002AD44D /* gist Extension.appex in Embed Foundation Extensions */, 79 | ); 80 | name = "Embed Foundation Extensions"; 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | ADB4093328D2ED07002AD44D /* Embed Foundation Extensions */ = { 84 | isa = PBXCopyFilesBuildPhase; 85 | buildActionMask = 2147483647; 86 | dstPath = ""; 87 | dstSubfolderSpec = 13; 88 | files = ( 89 | ADB4090328D2ED07002AD44D /* gist Extension.appex in Embed Foundation Extensions */, 90 | ); 91 | name = "Embed Foundation Extensions"; 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | /* End PBXCopyFilesBuildPhase section */ 95 | 96 | /* Begin PBXFileReference section */ 97 | AD15920128DDD53400506584 /* KeychainHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainHelper.swift; sourceTree = ""; }; 98 | AD15921428E97E8C00506584 /* gist-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "gist-icon.png"; sourceTree = ""; }; 99 | AD6CDBA928E9848900F1BCA1 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 100 | ADB408C528D2ED06002AD44D /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = Base; path = ../Base.lproj/Main.html; sourceTree = ""; }; 101 | ADB408C728D2ED06002AD44D /* Style.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = Style.css; sourceTree = ""; }; 102 | ADB408C828D2ED06002AD44D /* Script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = Script.js; sourceTree = ""; }; 103 | ADB408C928D2ED06002AD44D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 104 | ADB408CA28D2ED07002AD44D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 105 | ADB408CC28D2ED07002AD44D /* SafariWebExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariWebExtensionHandler.swift; sourceTree = ""; }; 106 | ADB408CE28D2ED07002AD44D /* _locales */ = {isa = PBXFileReference; lastKnownFileType = folder; path = _locales; sourceTree = ""; }; 107 | ADB408CF28D2ED07002AD44D /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; path = images; sourceTree = ""; }; 108 | ADB408D028D2ED07002AD44D /* manifest.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = manifest.json; sourceTree = ""; }; 109 | ADB408D128D2ED07002AD44D /* background.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = background.js; sourceTree = ""; }; 110 | ADB408D228D2ED07002AD44D /* content.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = content.js; sourceTree = ""; }; 111 | ADB408D328D2ED07002AD44D /* popup.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = popup.html; sourceTree = ""; }; 112 | ADB408D428D2ED07002AD44D /* popup.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = popup.css; sourceTree = ""; }; 113 | ADB408D528D2ED07002AD44D /* popup.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = popup.js; sourceTree = ""; }; 114 | ADB408DA28D2ED07002AD44D /* gist.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = gist.app; sourceTree = BUILT_PRODUCTS_DIR; }; 115 | ADB408DD28D2ED07002AD44D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 116 | ADB408DF28D2ED07002AD44D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 117 | ADB408E228D2ED07002AD44D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 118 | ADB408E528D2ED07002AD44D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 119 | ADB408E728D2ED07002AD44D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 120 | ADB408EC28D2ED07002AD44D /* gist.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = gist.app; sourceTree = BUILT_PRODUCTS_DIR; }; 121 | ADB408EE28D2ED07002AD44D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 122 | ADB408F128D2ED07002AD44D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 123 | ADB408F328D2ED07002AD44D /* gist.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = gist.entitlements; sourceTree = ""; }; 124 | ADB408F828D2ED07002AD44D /* gist Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "gist Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 125 | ADB408FD28D2ED07002AD44D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 126 | ADB4090228D2ED07002AD44D /* gist Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "gist Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 127 | ADB4090728D2ED07002AD44D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 128 | ADB4090828D2ED07002AD44D /* gist.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = gist.entitlements; sourceTree = ""; }; 129 | /* End PBXFileReference section */ 130 | 131 | /* Begin PBXFrameworksBuildPhase section */ 132 | ADB408D728D2ED07002AD44D /* Frameworks */ = { 133 | isa = PBXFrameworksBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | ); 137 | runOnlyForDeploymentPostprocessing = 0; 138 | }; 139 | ADB408E928D2ED07002AD44D /* Frameworks */ = { 140 | isa = PBXFrameworksBuildPhase; 141 | buildActionMask = 2147483647; 142 | files = ( 143 | ); 144 | runOnlyForDeploymentPostprocessing = 0; 145 | }; 146 | ADB408F528D2ED07002AD44D /* Frameworks */ = { 147 | isa = PBXFrameworksBuildPhase; 148 | buildActionMask = 2147483647; 149 | files = ( 150 | ); 151 | runOnlyForDeploymentPostprocessing = 0; 152 | }; 153 | ADB408FF28D2ED07002AD44D /* Frameworks */ = { 154 | isa = PBXFrameworksBuildPhase; 155 | buildActionMask = 2147483647; 156 | files = ( 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | /* End PBXFrameworksBuildPhase section */ 161 | 162 | /* Begin PBXGroup section */ 163 | ADB408BD28D2ED06002AD44D = { 164 | isa = PBXGroup; 165 | children = ( 166 | AD6CDBA928E9848900F1BCA1 /* README.md */, 167 | ADB408C228D2ED06002AD44D /* Shared (App) */, 168 | ADB408CB28D2ED07002AD44D /* Shared (Extension) */, 169 | ADB408DC28D2ED07002AD44D /* iOS (App) */, 170 | ADB408ED28D2ED07002AD44D /* macOS (App) */, 171 | ADB408FC28D2ED07002AD44D /* iOS (Extension) */, 172 | ADB4090628D2ED07002AD44D /* macOS (Extension) */, 173 | ADB408DB28D2ED07002AD44D /* Products */, 174 | ); 175 | sourceTree = ""; 176 | }; 177 | ADB408C228D2ED06002AD44D /* Shared (App) */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | ADB408C928D2ED06002AD44D /* ViewController.swift */, 181 | AD15920128DDD53400506584 /* KeychainHelper.swift */, 182 | ADB408CA28D2ED07002AD44D /* Assets.xcassets */, 183 | ADB408C328D2ED06002AD44D /* Resources */, 184 | ); 185 | path = "Shared (App)"; 186 | sourceTree = ""; 187 | }; 188 | ADB408C328D2ED06002AD44D /* Resources */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | ADB408C428D2ED06002AD44D /* Main.html */, 192 | AD15921428E97E8C00506584 /* gist-icon.png */, 193 | ADB408C728D2ED06002AD44D /* Style.css */, 194 | ADB408C828D2ED06002AD44D /* Script.js */, 195 | ); 196 | path = Resources; 197 | sourceTree = ""; 198 | }; 199 | ADB408CB28D2ED07002AD44D /* Shared (Extension) */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | ADB408CC28D2ED07002AD44D /* SafariWebExtensionHandler.swift */, 203 | ADB408CD28D2ED07002AD44D /* Resources */, 204 | ); 205 | path = "Shared (Extension)"; 206 | sourceTree = ""; 207 | }; 208 | ADB408CD28D2ED07002AD44D /* Resources */ = { 209 | isa = PBXGroup; 210 | children = ( 211 | ADB408CE28D2ED07002AD44D /* _locales */, 212 | ADB408CF28D2ED07002AD44D /* images */, 213 | ADB408D028D2ED07002AD44D /* manifest.json */, 214 | ADB408D128D2ED07002AD44D /* background.js */, 215 | ADB408D228D2ED07002AD44D /* content.js */, 216 | ADB408D328D2ED07002AD44D /* popup.html */, 217 | ADB408D428D2ED07002AD44D /* popup.css */, 218 | ADB408D528D2ED07002AD44D /* popup.js */, 219 | ); 220 | path = Resources; 221 | sourceTree = ""; 222 | }; 223 | ADB408DB28D2ED07002AD44D /* Products */ = { 224 | isa = PBXGroup; 225 | children = ( 226 | ADB408DA28D2ED07002AD44D /* gist.app */, 227 | ADB408EC28D2ED07002AD44D /* gist.app */, 228 | ADB408F828D2ED07002AD44D /* gist Extension.appex */, 229 | ADB4090228D2ED07002AD44D /* gist Extension.appex */, 230 | ); 231 | name = Products; 232 | sourceTree = ""; 233 | }; 234 | ADB408DC28D2ED07002AD44D /* iOS (App) */ = { 235 | isa = PBXGroup; 236 | children = ( 237 | ADB408DD28D2ED07002AD44D /* AppDelegate.swift */, 238 | ADB408DF28D2ED07002AD44D /* SceneDelegate.swift */, 239 | ADB408E128D2ED07002AD44D /* LaunchScreen.storyboard */, 240 | ADB408E428D2ED07002AD44D /* Main.storyboard */, 241 | ADB408E728D2ED07002AD44D /* Info.plist */, 242 | ); 243 | path = "iOS (App)"; 244 | sourceTree = ""; 245 | }; 246 | ADB408ED28D2ED07002AD44D /* macOS (App) */ = { 247 | isa = PBXGroup; 248 | children = ( 249 | ADB408EE28D2ED07002AD44D /* AppDelegate.swift */, 250 | ADB408F028D2ED07002AD44D /* Main.storyboard */, 251 | ADB408F328D2ED07002AD44D /* gist.entitlements */, 252 | ); 253 | path = "macOS (App)"; 254 | sourceTree = ""; 255 | }; 256 | ADB408FC28D2ED07002AD44D /* iOS (Extension) */ = { 257 | isa = PBXGroup; 258 | children = ( 259 | ADB408FD28D2ED07002AD44D /* Info.plist */, 260 | ); 261 | path = "iOS (Extension)"; 262 | sourceTree = ""; 263 | }; 264 | ADB4090628D2ED07002AD44D /* macOS (Extension) */ = { 265 | isa = PBXGroup; 266 | children = ( 267 | ADB4090728D2ED07002AD44D /* Info.plist */, 268 | ADB4090828D2ED07002AD44D /* gist.entitlements */, 269 | ); 270 | path = "macOS (Extension)"; 271 | sourceTree = ""; 272 | }; 273 | /* End PBXGroup section */ 274 | 275 | /* Begin PBXNativeTarget section */ 276 | ADB408D928D2ED07002AD44D /* gist (iOS) */ = { 277 | isa = PBXNativeTarget; 278 | buildConfigurationList = ADB4092D28D2ED07002AD44D /* Build configuration list for PBXNativeTarget "gist (iOS)" */; 279 | buildPhases = ( 280 | ADB408D628D2ED07002AD44D /* Sources */, 281 | ADB408D728D2ED07002AD44D /* Frameworks */, 282 | ADB408D828D2ED07002AD44D /* Resources */, 283 | ADB4092C28D2ED07002AD44D /* Embed Foundation Extensions */, 284 | ); 285 | buildRules = ( 286 | ); 287 | dependencies = ( 288 | ADB408FB28D2ED07002AD44D /* PBXTargetDependency */, 289 | ); 290 | name = "gist (iOS)"; 291 | productName = "gist (iOS)"; 292 | productReference = ADB408DA28D2ED07002AD44D /* gist.app */; 293 | productType = "com.apple.product-type.application"; 294 | }; 295 | ADB408EB28D2ED07002AD44D /* gist (macOS) */ = { 296 | isa = PBXNativeTarget; 297 | buildConfigurationList = ADB4093428D2ED07002AD44D /* Build configuration list for PBXNativeTarget "gist (macOS)" */; 298 | buildPhases = ( 299 | ADB408E828D2ED07002AD44D /* Sources */, 300 | ADB408E928D2ED07002AD44D /* Frameworks */, 301 | ADB408EA28D2ED07002AD44D /* Resources */, 302 | ADB4093328D2ED07002AD44D /* Embed Foundation Extensions */, 303 | ); 304 | buildRules = ( 305 | ); 306 | dependencies = ( 307 | ADB4090528D2ED07002AD44D /* PBXTargetDependency */, 308 | ); 309 | name = "gist (macOS)"; 310 | productName = "gist (macOS)"; 311 | productReference = ADB408EC28D2ED07002AD44D /* gist.app */; 312 | productType = "com.apple.product-type.application"; 313 | }; 314 | ADB408F728D2ED07002AD44D /* gist Extension (iOS) */ = { 315 | isa = PBXNativeTarget; 316 | buildConfigurationList = ADB4092928D2ED07002AD44D /* Build configuration list for PBXNativeTarget "gist Extension (iOS)" */; 317 | buildPhases = ( 318 | ADB408F428D2ED07002AD44D /* Sources */, 319 | ADB408F528D2ED07002AD44D /* Frameworks */, 320 | ADB408F628D2ED07002AD44D /* Resources */, 321 | ); 322 | buildRules = ( 323 | ); 324 | dependencies = ( 325 | ); 326 | name = "gist Extension (iOS)"; 327 | productName = "gist Extension (iOS)"; 328 | productReference = ADB408F828D2ED07002AD44D /* gist Extension.appex */; 329 | productType = "com.apple.product-type.app-extension"; 330 | }; 331 | ADB4090128D2ED07002AD44D /* gist Extension (macOS) */ = { 332 | isa = PBXNativeTarget; 333 | buildConfigurationList = ADB4093028D2ED07002AD44D /* Build configuration list for PBXNativeTarget "gist Extension (macOS)" */; 334 | buildPhases = ( 335 | ADB408FE28D2ED07002AD44D /* Sources */, 336 | ADB408FF28D2ED07002AD44D /* Frameworks */, 337 | ADB4090028D2ED07002AD44D /* Resources */, 338 | ); 339 | buildRules = ( 340 | ); 341 | dependencies = ( 342 | ); 343 | name = "gist Extension (macOS)"; 344 | productName = "gist Extension (macOS)"; 345 | productReference = ADB4090228D2ED07002AD44D /* gist Extension.appex */; 346 | productType = "com.apple.product-type.app-extension"; 347 | }; 348 | /* End PBXNativeTarget section */ 349 | 350 | /* Begin PBXProject section */ 351 | ADB408BE28D2ED06002AD44D /* Project object */ = { 352 | isa = PBXProject; 353 | attributes = { 354 | BuildIndependentTargetsInParallel = 1; 355 | LastSwiftUpdateCheck = 1400; 356 | LastUpgradeCheck = 1400; 357 | TargetAttributes = { 358 | ADB408D928D2ED07002AD44D = { 359 | CreatedOnToolsVersion = 14.0; 360 | }; 361 | ADB408EB28D2ED07002AD44D = { 362 | CreatedOnToolsVersion = 14.0; 363 | }; 364 | ADB408F728D2ED07002AD44D = { 365 | CreatedOnToolsVersion = 14.0; 366 | }; 367 | ADB4090128D2ED07002AD44D = { 368 | CreatedOnToolsVersion = 14.0; 369 | }; 370 | }; 371 | }; 372 | buildConfigurationList = ADB408C128D2ED06002AD44D /* Build configuration list for PBXProject "gist" */; 373 | compatibilityVersion = "Xcode 14.0"; 374 | developmentRegion = en; 375 | hasScannedForEncodings = 0; 376 | knownRegions = ( 377 | en, 378 | Base, 379 | ); 380 | mainGroup = ADB408BD28D2ED06002AD44D; 381 | productRefGroup = ADB408DB28D2ED07002AD44D /* Products */; 382 | projectDirPath = ""; 383 | projectRoot = ""; 384 | targets = ( 385 | ADB408D928D2ED07002AD44D /* gist (iOS) */, 386 | ADB408EB28D2ED07002AD44D /* gist (macOS) */, 387 | ADB408F728D2ED07002AD44D /* gist Extension (iOS) */, 388 | ADB4090128D2ED07002AD44D /* gist Extension (macOS) */, 389 | ); 390 | }; 391 | /* End PBXProject section */ 392 | 393 | /* Begin PBXResourcesBuildPhase section */ 394 | ADB408D828D2ED07002AD44D /* Resources */ = { 395 | isa = PBXResourcesBuildPhase; 396 | buildActionMask = 2147483647; 397 | files = ( 398 | AD15921528E97E8C00506584 /* gist-icon.png in Resources */, 399 | ADB408E328D2ED07002AD44D /* LaunchScreen.storyboard in Resources */, 400 | ADB4090928D2ED07002AD44D /* Main.html in Resources */, 401 | ADB4090F28D2ED07002AD44D /* Script.js in Resources */, 402 | ADB4091328D2ED07002AD44D /* Assets.xcassets in Resources */, 403 | ADB408E628D2ED07002AD44D /* Main.storyboard in Resources */, 404 | ADB4090D28D2ED07002AD44D /* Style.css in Resources */, 405 | ); 406 | runOnlyForDeploymentPostprocessing = 0; 407 | }; 408 | ADB408EA28D2ED07002AD44D /* Resources */ = { 409 | isa = PBXResourcesBuildPhase; 410 | buildActionMask = 2147483647; 411 | files = ( 412 | ADB4090E28D2ED07002AD44D /* Style.css in Resources */, 413 | ADB408F228D2ED07002AD44D /* Main.storyboard in Resources */, 414 | ADB4091028D2ED07002AD44D /* Script.js in Resources */, 415 | AD15921628E97E8C00506584 /* gist-icon.png in Resources */, 416 | ADB4091428D2ED07002AD44D /* Assets.xcassets in Resources */, 417 | ADB4090A28D2ED07002AD44D /* Main.html in Resources */, 418 | ); 419 | runOnlyForDeploymentPostprocessing = 0; 420 | }; 421 | ADB408F628D2ED07002AD44D /* Resources */ = { 422 | isa = PBXResourcesBuildPhase; 423 | buildActionMask = 2147483647; 424 | files = ( 425 | ADB4091D28D2ED07002AD44D /* background.js in Resources */, 426 | ADB4092328D2ED07002AD44D /* popup.css in Resources */, 427 | ADB4092128D2ED07002AD44D /* popup.html in Resources */, 428 | ADB4091928D2ED07002AD44D /* images in Resources */, 429 | ADB4091B28D2ED07002AD44D /* manifest.json in Resources */, 430 | ADB4091728D2ED07002AD44D /* _locales in Resources */, 431 | ADB4091F28D2ED07002AD44D /* content.js in Resources */, 432 | ADB4092528D2ED07002AD44D /* popup.js in Resources */, 433 | ); 434 | runOnlyForDeploymentPostprocessing = 0; 435 | }; 436 | ADB4090028D2ED07002AD44D /* Resources */ = { 437 | isa = PBXResourcesBuildPhase; 438 | buildActionMask = 2147483647; 439 | files = ( 440 | ADB4091E28D2ED07002AD44D /* background.js in Resources */, 441 | ADB4092428D2ED07002AD44D /* popup.css in Resources */, 442 | ADB4092228D2ED07002AD44D /* popup.html in Resources */, 443 | ADB4091A28D2ED07002AD44D /* images in Resources */, 444 | ADB4091C28D2ED07002AD44D /* manifest.json in Resources */, 445 | ADB4091828D2ED07002AD44D /* _locales in Resources */, 446 | ADB4092028D2ED07002AD44D /* content.js in Resources */, 447 | ADB4092628D2ED07002AD44D /* popup.js in Resources */, 448 | ); 449 | runOnlyForDeploymentPostprocessing = 0; 450 | }; 451 | /* End PBXResourcesBuildPhase section */ 452 | 453 | /* Begin PBXSourcesBuildPhase section */ 454 | ADB408D628D2ED07002AD44D /* Sources */ = { 455 | isa = PBXSourcesBuildPhase; 456 | buildActionMask = 2147483647; 457 | files = ( 458 | ADB4091128D2ED07002AD44D /* ViewController.swift in Sources */, 459 | ADB408DE28D2ED07002AD44D /* AppDelegate.swift in Sources */, 460 | ADB408E028D2ED07002AD44D /* SceneDelegate.swift in Sources */, 461 | AD15920228DDD53400506584 /* KeychainHelper.swift in Sources */, 462 | ); 463 | runOnlyForDeploymentPostprocessing = 0; 464 | }; 465 | ADB408E828D2ED07002AD44D /* Sources */ = { 466 | isa = PBXSourcesBuildPhase; 467 | buildActionMask = 2147483647; 468 | files = ( 469 | ADB4091228D2ED07002AD44D /* ViewController.swift in Sources */, 470 | AD15920328DDD53400506584 /* KeychainHelper.swift in Sources */, 471 | ADB408EF28D2ED07002AD44D /* AppDelegate.swift in Sources */, 472 | ); 473 | runOnlyForDeploymentPostprocessing = 0; 474 | }; 475 | ADB408F428D2ED07002AD44D /* Sources */ = { 476 | isa = PBXSourcesBuildPhase; 477 | buildActionMask = 2147483647; 478 | files = ( 479 | ADB4091528D2ED07002AD44D /* SafariWebExtensionHandler.swift in Sources */, 480 | AD15920428DEC78D00506584 /* KeychainHelper.swift in Sources */, 481 | ); 482 | runOnlyForDeploymentPostprocessing = 0; 483 | }; 484 | ADB408FE28D2ED07002AD44D /* Sources */ = { 485 | isa = PBXSourcesBuildPhase; 486 | buildActionMask = 2147483647; 487 | files = ( 488 | ADB4091628D2ED07002AD44D /* SafariWebExtensionHandler.swift in Sources */, 489 | AD15920528DEC78E00506584 /* KeychainHelper.swift in Sources */, 490 | ); 491 | runOnlyForDeploymentPostprocessing = 0; 492 | }; 493 | /* End PBXSourcesBuildPhase section */ 494 | 495 | /* Begin PBXTargetDependency section */ 496 | ADB408FB28D2ED07002AD44D /* PBXTargetDependency */ = { 497 | isa = PBXTargetDependency; 498 | target = ADB408F728D2ED07002AD44D /* gist Extension (iOS) */; 499 | targetProxy = ADB408FA28D2ED07002AD44D /* PBXContainerItemProxy */; 500 | }; 501 | ADB4090528D2ED07002AD44D /* PBXTargetDependency */ = { 502 | isa = PBXTargetDependency; 503 | target = ADB4090128D2ED07002AD44D /* gist Extension (macOS) */; 504 | targetProxy = ADB4090428D2ED07002AD44D /* PBXContainerItemProxy */; 505 | }; 506 | /* End PBXTargetDependency section */ 507 | 508 | /* Begin PBXVariantGroup section */ 509 | ADB408C428D2ED06002AD44D /* Main.html */ = { 510 | isa = PBXVariantGroup; 511 | children = ( 512 | ADB408C528D2ED06002AD44D /* Base */, 513 | ); 514 | name = Main.html; 515 | sourceTree = ""; 516 | }; 517 | ADB408E128D2ED07002AD44D /* LaunchScreen.storyboard */ = { 518 | isa = PBXVariantGroup; 519 | children = ( 520 | ADB408E228D2ED07002AD44D /* Base */, 521 | ); 522 | name = LaunchScreen.storyboard; 523 | sourceTree = ""; 524 | }; 525 | ADB408E428D2ED07002AD44D /* Main.storyboard */ = { 526 | isa = PBXVariantGroup; 527 | children = ( 528 | ADB408E528D2ED07002AD44D /* Base */, 529 | ); 530 | name = Main.storyboard; 531 | sourceTree = ""; 532 | }; 533 | ADB408F028D2ED07002AD44D /* Main.storyboard */ = { 534 | isa = PBXVariantGroup; 535 | children = ( 536 | ADB408F128D2ED07002AD44D /* Base */, 537 | ); 538 | name = Main.storyboard; 539 | sourceTree = ""; 540 | }; 541 | /* End PBXVariantGroup section */ 542 | 543 | /* Begin XCBuildConfiguration section */ 544 | ADB4092728D2ED07002AD44D /* Debug */ = { 545 | isa = XCBuildConfiguration; 546 | buildSettings = { 547 | ALWAYS_SEARCH_USER_PATHS = NO; 548 | CLANG_ANALYZER_NONNULL = YES; 549 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 550 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 551 | CLANG_ENABLE_MODULES = YES; 552 | CLANG_ENABLE_OBJC_ARC = YES; 553 | CLANG_ENABLE_OBJC_WEAK = YES; 554 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 555 | CLANG_WARN_BOOL_CONVERSION = YES; 556 | CLANG_WARN_COMMA = YES; 557 | CLANG_WARN_CONSTANT_CONVERSION = YES; 558 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 559 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 560 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 561 | CLANG_WARN_EMPTY_BODY = YES; 562 | CLANG_WARN_ENUM_CONVERSION = YES; 563 | CLANG_WARN_INFINITE_RECURSION = YES; 564 | CLANG_WARN_INT_CONVERSION = YES; 565 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 566 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 567 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 568 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 569 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 570 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 571 | CLANG_WARN_STRICT_PROTOTYPES = YES; 572 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 573 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 574 | CLANG_WARN_UNREACHABLE_CODE = YES; 575 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 576 | COPY_PHASE_STRIP = NO; 577 | DEBUG_INFORMATION_FORMAT = dwarf; 578 | ENABLE_STRICT_OBJC_MSGSEND = YES; 579 | ENABLE_TESTABILITY = YES; 580 | GCC_C_LANGUAGE_STANDARD = gnu11; 581 | GCC_DYNAMIC_NO_PIC = NO; 582 | GCC_NO_COMMON_BLOCKS = YES; 583 | GCC_OPTIMIZATION_LEVEL = 0; 584 | GCC_PREPROCESSOR_DEFINITIONS = ( 585 | "DEBUG=1", 586 | "$(inherited)", 587 | ); 588 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 589 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 590 | GCC_WARN_UNDECLARED_SELECTOR = YES; 591 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 592 | GCC_WARN_UNUSED_FUNCTION = YES; 593 | GCC_WARN_UNUSED_VARIABLE = YES; 594 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 595 | MTL_FAST_MATH = YES; 596 | ONLY_ACTIVE_ARCH = YES; 597 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 598 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 599 | }; 600 | name = Debug; 601 | }; 602 | ADB4092828D2ED07002AD44D /* Release */ = { 603 | isa = XCBuildConfiguration; 604 | buildSettings = { 605 | ALWAYS_SEARCH_USER_PATHS = NO; 606 | CLANG_ANALYZER_NONNULL = YES; 607 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 608 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 609 | CLANG_ENABLE_MODULES = YES; 610 | CLANG_ENABLE_OBJC_ARC = YES; 611 | CLANG_ENABLE_OBJC_WEAK = YES; 612 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 613 | CLANG_WARN_BOOL_CONVERSION = YES; 614 | CLANG_WARN_COMMA = YES; 615 | CLANG_WARN_CONSTANT_CONVERSION = YES; 616 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 617 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 618 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 619 | CLANG_WARN_EMPTY_BODY = YES; 620 | CLANG_WARN_ENUM_CONVERSION = YES; 621 | CLANG_WARN_INFINITE_RECURSION = YES; 622 | CLANG_WARN_INT_CONVERSION = YES; 623 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 624 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 625 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 626 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 627 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 628 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 629 | CLANG_WARN_STRICT_PROTOTYPES = YES; 630 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 631 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 632 | CLANG_WARN_UNREACHABLE_CODE = YES; 633 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 634 | COPY_PHASE_STRIP = NO; 635 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 636 | ENABLE_NS_ASSERTIONS = NO; 637 | ENABLE_STRICT_OBJC_MSGSEND = YES; 638 | GCC_C_LANGUAGE_STANDARD = gnu11; 639 | GCC_NO_COMMON_BLOCKS = YES; 640 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 641 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 642 | GCC_WARN_UNDECLARED_SELECTOR = YES; 643 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 644 | GCC_WARN_UNUSED_FUNCTION = YES; 645 | GCC_WARN_UNUSED_VARIABLE = YES; 646 | MTL_ENABLE_DEBUG_INFO = NO; 647 | MTL_FAST_MATH = YES; 648 | SWIFT_COMPILATION_MODE = wholemodule; 649 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 650 | }; 651 | name = Release; 652 | }; 653 | ADB4092A28D2ED07002AD44D /* Debug */ = { 654 | isa = XCBuildConfiguration; 655 | buildSettings = { 656 | CODE_SIGN_STYLE = Automatic; 657 | CURRENT_PROJECT_VERSION = 1; 658 | DEVELOPMENT_TEAM = CH98WW8RDP; 659 | GENERATE_INFOPLIST_FILE = YES; 660 | INFOPLIST_FILE = "iOS (Extension)/Info.plist"; 661 | INFOPLIST_KEY_CFBundleDisplayName = "gist Extension"; 662 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 663 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 664 | LD_RUNPATH_SEARCH_PATHS = ( 665 | "$(inherited)", 666 | "@executable_path/Frameworks", 667 | "@executable_path/../../Frameworks", 668 | ); 669 | MARKETING_VERSION = 1.0; 670 | OTHER_LDFLAGS = ( 671 | "-framework", 672 | SafariServices, 673 | ); 674 | PRODUCT_BUNDLE_IDENTIFIER = com.simicvm.gist.Extension; 675 | PRODUCT_NAME = "gist Extension"; 676 | SDKROOT = iphoneos; 677 | SKIP_INSTALL = YES; 678 | SWIFT_EMIT_LOC_STRINGS = YES; 679 | SWIFT_VERSION = 5.0; 680 | TARGETED_DEVICE_FAMILY = "1,2"; 681 | }; 682 | name = Debug; 683 | }; 684 | ADB4092B28D2ED07002AD44D /* Release */ = { 685 | isa = XCBuildConfiguration; 686 | buildSettings = { 687 | CODE_SIGN_STYLE = Automatic; 688 | CURRENT_PROJECT_VERSION = 1; 689 | DEVELOPMENT_TEAM = CH98WW8RDP; 690 | GENERATE_INFOPLIST_FILE = YES; 691 | INFOPLIST_FILE = "iOS (Extension)/Info.plist"; 692 | INFOPLIST_KEY_CFBundleDisplayName = "gist Extension"; 693 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 694 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 695 | LD_RUNPATH_SEARCH_PATHS = ( 696 | "$(inherited)", 697 | "@executable_path/Frameworks", 698 | "@executable_path/../../Frameworks", 699 | ); 700 | MARKETING_VERSION = 1.0; 701 | OTHER_LDFLAGS = ( 702 | "-framework", 703 | SafariServices, 704 | ); 705 | PRODUCT_BUNDLE_IDENTIFIER = com.simicvm.gist.Extension; 706 | PRODUCT_NAME = "gist Extension"; 707 | SDKROOT = iphoneos; 708 | SKIP_INSTALL = YES; 709 | SWIFT_EMIT_LOC_STRINGS = YES; 710 | SWIFT_VERSION = 5.0; 711 | TARGETED_DEVICE_FAMILY = "1,2"; 712 | VALIDATE_PRODUCT = YES; 713 | }; 714 | name = Release; 715 | }; 716 | ADB4092E28D2ED07002AD44D /* Debug */ = { 717 | isa = XCBuildConfiguration; 718 | buildSettings = { 719 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 720 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 721 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 722 | CODE_SIGN_STYLE = Automatic; 723 | CURRENT_PROJECT_VERSION = 1; 724 | DEVELOPMENT_TEAM = CH98WW8RDP; 725 | GENERATE_INFOPLIST_FILE = YES; 726 | INFOPLIST_FILE = "iOS (App)/Info.plist"; 727 | INFOPLIST_KEY_CFBundleDisplayName = gist; 728 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 729 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 730 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 731 | INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 732 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 733 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 734 | LD_RUNPATH_SEARCH_PATHS = ( 735 | "$(inherited)", 736 | "@executable_path/Frameworks", 737 | ); 738 | MARKETING_VERSION = 1.0; 739 | OTHER_LDFLAGS = ( 740 | "-framework", 741 | SafariServices, 742 | "-framework", 743 | WebKit, 744 | ); 745 | PRODUCT_BUNDLE_IDENTIFIER = com.simicvm.gist; 746 | PRODUCT_NAME = gist; 747 | SDKROOT = iphoneos; 748 | SWIFT_EMIT_LOC_STRINGS = YES; 749 | SWIFT_VERSION = 5.0; 750 | TARGETED_DEVICE_FAMILY = "1,2"; 751 | }; 752 | name = Debug; 753 | }; 754 | ADB4092F28D2ED07002AD44D /* Release */ = { 755 | isa = XCBuildConfiguration; 756 | buildSettings = { 757 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 758 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 759 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 760 | CODE_SIGN_STYLE = Automatic; 761 | CURRENT_PROJECT_VERSION = 1; 762 | DEVELOPMENT_TEAM = CH98WW8RDP; 763 | GENERATE_INFOPLIST_FILE = YES; 764 | INFOPLIST_FILE = "iOS (App)/Info.plist"; 765 | INFOPLIST_KEY_CFBundleDisplayName = gist; 766 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 767 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 768 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 769 | INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 770 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 771 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 772 | LD_RUNPATH_SEARCH_PATHS = ( 773 | "$(inherited)", 774 | "@executable_path/Frameworks", 775 | ); 776 | MARKETING_VERSION = 1.0; 777 | OTHER_LDFLAGS = ( 778 | "-framework", 779 | SafariServices, 780 | "-framework", 781 | WebKit, 782 | ); 783 | PRODUCT_BUNDLE_IDENTIFIER = com.simicvm.gist; 784 | PRODUCT_NAME = gist; 785 | SDKROOT = iphoneos; 786 | SWIFT_EMIT_LOC_STRINGS = YES; 787 | SWIFT_VERSION = 5.0; 788 | TARGETED_DEVICE_FAMILY = "1,2"; 789 | VALIDATE_PRODUCT = YES; 790 | }; 791 | name = Release; 792 | }; 793 | ADB4093128D2ED07002AD44D /* Debug */ = { 794 | isa = XCBuildConfiguration; 795 | buildSettings = { 796 | CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/gist.entitlements"; 797 | CODE_SIGN_STYLE = Automatic; 798 | CURRENT_PROJECT_VERSION = 1; 799 | DEVELOPMENT_TEAM = CH98WW8RDP; 800 | ENABLE_HARDENED_RUNTIME = YES; 801 | GENERATE_INFOPLIST_FILE = YES; 802 | INFOPLIST_FILE = "macOS (Extension)/Info.plist"; 803 | INFOPLIST_KEY_CFBundleDisplayName = "gist Extension"; 804 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 805 | LD_RUNPATH_SEARCH_PATHS = ( 806 | "$(inherited)", 807 | "@executable_path/../Frameworks", 808 | "@executable_path/../../../../Frameworks", 809 | ); 810 | MACOSX_DEPLOYMENT_TARGET = 10.14; 811 | MARKETING_VERSION = 1.0; 812 | OTHER_LDFLAGS = ( 813 | "-framework", 814 | SafariServices, 815 | ); 816 | PRODUCT_BUNDLE_IDENTIFIER = com.simicvm.gist.Extension; 817 | PRODUCT_NAME = "gist Extension"; 818 | SDKROOT = macosx; 819 | SKIP_INSTALL = YES; 820 | SWIFT_EMIT_LOC_STRINGS = YES; 821 | SWIFT_VERSION = 5.0; 822 | }; 823 | name = Debug; 824 | }; 825 | ADB4093228D2ED07002AD44D /* Release */ = { 826 | isa = XCBuildConfiguration; 827 | buildSettings = { 828 | CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/gist.entitlements"; 829 | CODE_SIGN_STYLE = Automatic; 830 | CURRENT_PROJECT_VERSION = 1; 831 | DEVELOPMENT_TEAM = CH98WW8RDP; 832 | ENABLE_HARDENED_RUNTIME = YES; 833 | GENERATE_INFOPLIST_FILE = YES; 834 | INFOPLIST_FILE = "macOS (Extension)/Info.plist"; 835 | INFOPLIST_KEY_CFBundleDisplayName = "gist Extension"; 836 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 837 | LD_RUNPATH_SEARCH_PATHS = ( 838 | "$(inherited)", 839 | "@executable_path/../Frameworks", 840 | "@executable_path/../../../../Frameworks", 841 | ); 842 | MACOSX_DEPLOYMENT_TARGET = 10.14; 843 | MARKETING_VERSION = 1.0; 844 | OTHER_LDFLAGS = ( 845 | "-framework", 846 | SafariServices, 847 | ); 848 | PRODUCT_BUNDLE_IDENTIFIER = com.simicvm.gist.Extension; 849 | PRODUCT_NAME = "gist Extension"; 850 | SDKROOT = macosx; 851 | SKIP_INSTALL = YES; 852 | SWIFT_EMIT_LOC_STRINGS = YES; 853 | SWIFT_VERSION = 5.0; 854 | }; 855 | name = Release; 856 | }; 857 | ADB4093528D2ED07002AD44D /* Debug */ = { 858 | isa = XCBuildConfiguration; 859 | buildSettings = { 860 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 861 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 862 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 863 | CODE_SIGN_ENTITLEMENTS = "macOS (App)/gist.entitlements"; 864 | CODE_SIGN_STYLE = Automatic; 865 | CURRENT_PROJECT_VERSION = 1; 866 | DEVELOPMENT_TEAM = CH98WW8RDP; 867 | ENABLE_HARDENED_RUNTIME = YES; 868 | GENERATE_INFOPLIST_FILE = YES; 869 | INFOPLIST_KEY_CFBundleDisplayName = gist; 870 | INFOPLIST_KEY_NSMainStoryboardFile = Main; 871 | INFOPLIST_KEY_NSPrincipalClass = NSApplication; 872 | LD_RUNPATH_SEARCH_PATHS = ( 873 | "$(inherited)", 874 | "@executable_path/../Frameworks", 875 | ); 876 | MACOSX_DEPLOYMENT_TARGET = 10.14; 877 | MARKETING_VERSION = 1.0; 878 | OTHER_LDFLAGS = ( 879 | "-framework", 880 | SafariServices, 881 | "-framework", 882 | WebKit, 883 | ); 884 | PRODUCT_BUNDLE_IDENTIFIER = com.simicvm.gist; 885 | PRODUCT_NAME = gist; 886 | SDKROOT = macosx; 887 | SWIFT_EMIT_LOC_STRINGS = YES; 888 | SWIFT_VERSION = 5.0; 889 | }; 890 | name = Debug; 891 | }; 892 | ADB4093628D2ED07002AD44D /* Release */ = { 893 | isa = XCBuildConfiguration; 894 | buildSettings = { 895 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 896 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 897 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 898 | CODE_SIGN_ENTITLEMENTS = "macOS (App)/gist.entitlements"; 899 | CODE_SIGN_STYLE = Automatic; 900 | CURRENT_PROJECT_VERSION = 1; 901 | DEVELOPMENT_TEAM = CH98WW8RDP; 902 | ENABLE_HARDENED_RUNTIME = YES; 903 | GENERATE_INFOPLIST_FILE = YES; 904 | INFOPLIST_KEY_CFBundleDisplayName = gist; 905 | INFOPLIST_KEY_NSMainStoryboardFile = Main; 906 | INFOPLIST_KEY_NSPrincipalClass = NSApplication; 907 | LD_RUNPATH_SEARCH_PATHS = ( 908 | "$(inherited)", 909 | "@executable_path/../Frameworks", 910 | ); 911 | MACOSX_DEPLOYMENT_TARGET = 10.14; 912 | MARKETING_VERSION = 1.0; 913 | OTHER_LDFLAGS = ( 914 | "-framework", 915 | SafariServices, 916 | "-framework", 917 | WebKit, 918 | ); 919 | PRODUCT_BUNDLE_IDENTIFIER = com.simicvm.gist; 920 | PRODUCT_NAME = gist; 921 | SDKROOT = macosx; 922 | SWIFT_EMIT_LOC_STRINGS = YES; 923 | SWIFT_VERSION = 5.0; 924 | }; 925 | name = Release; 926 | }; 927 | /* End XCBuildConfiguration section */ 928 | 929 | /* Begin XCConfigurationList section */ 930 | ADB408C128D2ED06002AD44D /* Build configuration list for PBXProject "gist" */ = { 931 | isa = XCConfigurationList; 932 | buildConfigurations = ( 933 | ADB4092728D2ED07002AD44D /* Debug */, 934 | ADB4092828D2ED07002AD44D /* Release */, 935 | ); 936 | defaultConfigurationIsVisible = 0; 937 | defaultConfigurationName = Release; 938 | }; 939 | ADB4092928D2ED07002AD44D /* Build configuration list for PBXNativeTarget "gist Extension (iOS)" */ = { 940 | isa = XCConfigurationList; 941 | buildConfigurations = ( 942 | ADB4092A28D2ED07002AD44D /* Debug */, 943 | ADB4092B28D2ED07002AD44D /* Release */, 944 | ); 945 | defaultConfigurationIsVisible = 0; 946 | defaultConfigurationName = Release; 947 | }; 948 | ADB4092D28D2ED07002AD44D /* Build configuration list for PBXNativeTarget "gist (iOS)" */ = { 949 | isa = XCConfigurationList; 950 | buildConfigurations = ( 951 | ADB4092E28D2ED07002AD44D /* Debug */, 952 | ADB4092F28D2ED07002AD44D /* Release */, 953 | ); 954 | defaultConfigurationIsVisible = 0; 955 | defaultConfigurationName = Release; 956 | }; 957 | ADB4093028D2ED07002AD44D /* Build configuration list for PBXNativeTarget "gist Extension (macOS)" */ = { 958 | isa = XCConfigurationList; 959 | buildConfigurations = ( 960 | ADB4093128D2ED07002AD44D /* Debug */, 961 | ADB4093228D2ED07002AD44D /* Release */, 962 | ); 963 | defaultConfigurationIsVisible = 0; 964 | defaultConfigurationName = Release; 965 | }; 966 | ADB4093428D2ED07002AD44D /* Build configuration list for PBXNativeTarget "gist (macOS)" */ = { 967 | isa = XCConfigurationList; 968 | buildConfigurations = ( 969 | ADB4093528D2ED07002AD44D /* Debug */, 970 | ADB4093628D2ED07002AD44D /* Release */, 971 | ); 972 | defaultConfigurationIsVisible = 0; 973 | defaultConfigurationName = Release; 974 | }; 975 | /* End XCConfigurationList section */ 976 | }; 977 | rootObject = ADB408BE28D2ED06002AD44D /* Project object */; 978 | } 979 | -------------------------------------------------------------------------------- /gist.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gist.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gist.xcodeproj/xcuserdata/marko.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | gist (iOS).xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | gist (macOS).xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /iOS (App)/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iOS (App) 4 | // 5 | // Created by Marko Simic on /915/22. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 21 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /iOS (App)/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /iOS (App)/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /iOS (App)/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /iOS (App)/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // iOS (App) 4 | // 5 | // Created by Marko Simic on /915/22. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 15 | guard let _ = (scene as? UIWindowScene) else { return } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /iOS (Extension)/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.Safari.web-extension 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /macOS (App)/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // macOS (App) 4 | // 5 | // Created by Marko Simic on /915/22. 6 | // 7 | 8 | import Cocoa 9 | 10 | @main 11 | class AppDelegate: NSObject, NSApplicationDelegate { 12 | 13 | func applicationDidFinishLaunching(_ notification: Notification) { 14 | // Override point for customization after application launch. 15 | } 16 | 17 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 18 | return true 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /macOS (App)/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 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 | -------------------------------------------------------------------------------- /macOS (App)/gist.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /macOS (Extension)/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.Safari.web-extension 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /macOS (Extension)/gist.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------