├── 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 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------