├── Menubar.acorn ├── ShelleyIcon.acorn ├── Shelley ├── Assets.xcassets │ ├── Contents.json │ ├── Icon.imageset │ │ ├── Icon.png │ │ └── Contents.json │ ├── Menubar.imageset │ │ ├── Menubar.png │ │ ├── Menubar-1.png │ │ └── Contents.json │ └── AppIcon.appiconset │ │ ├── icon-128.png │ │ ├── icon-16.png │ │ ├── icon-256.png │ │ ├── icon-32.png │ │ ├── icon-512.png │ │ ├── icon-16@2x.png │ │ ├── icon-32@2x.png │ │ ├── icon-128@2x.png │ │ ├── icon-256@2x.png │ │ ├── icon-512@2x.png │ │ └── Contents.json ├── Shelley-Bridging-Header.h ├── Defaults.plist ├── Extensions.swift ├── WelcomePopover.swift ├── AboutWindowController.swift ├── PrefsWindowController.swift ├── TaskRunner.swift ├── Info.plist ├── Constants.swift ├── MenuBarStatusItem.swift ├── Server.swift ├── AppDelegate.swift ├── AboutWindowController.xib ├── WelcomePopover.xib ├── PrefsWindowController.xib └── Base.lproj │ └── MainMenu.xib ├── Podfile ├── Shelley.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── thall.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── project.pbxproj ├── Shelley.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── README.md ├── Podfile.lock ├── LICENSE.md └── .gitignore /Menubar.acorn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Menubar.acorn -------------------------------------------------------------------------------- /ShelleyIcon.acorn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/ShelleyIcon.acorn -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/Icon.imageset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/Icon.imageset/Icon.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/Menubar.imageset/Menubar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/Menubar.imageset/Menubar.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-128.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-16.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-256.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-32.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-512.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/Menubar.imageset/Menubar-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/Menubar.imageset/Menubar-1.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-16@2x.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-32@2x.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-128@2x.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/icon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/Shelley/HEAD/Shelley/Assets.xcassets/AppIcon.appiconset/icon-512@2x.png -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | target "Shelley" do 4 | platform :osx, "10.14" 5 | inhibit_all_warnings! 6 | pod 'Sparkle' 7 | pod 'Criollo', '~> 0.5' 8 | end 9 | -------------------------------------------------------------------------------- /Shelley/Shelley-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | #import 7 | -------------------------------------------------------------------------------- /Shelley/Defaults.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Shelley.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Shelley.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Shelley.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Shelley.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Shelley is a tiny macOS menu bar app that lets you run commands on your Mac by issuing an HTTP request from another device. 2 | 3 | [You can read the story behind the app and how to use it on my blog](https://tyler.io/shelley/). 4 | 5 | The Shelley app icon is made by Freepik from www.flaticon.com 6 | -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/Icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Icon.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Shelley/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // Shelley 4 | // 5 | // Created by Tyler Hall on 8/26/20. 6 | // Copyright © 2020 Tyler Hall. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | extension NSEvent { 12 | var isRightClick: Bool { 13 | let rightClick = (self.type == .rightMouseDown) 14 | let controlClick = self.modifierFlags.contains(.control) 15 | return rightClick || controlClick 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/Menubar.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Menubar-1.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "Menubar.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "template" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Shelley.xcodeproj/xcuserdata/thall.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RequestBar.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 3 11 | 12 | Shelley.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 4 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CocoaAsyncSocket (7.6.4) 3 | - Criollo (0.5.5): 4 | - CocoaAsyncSocket (~> 7.6) 5 | - Sparkle (1.23.0) 6 | 7 | DEPENDENCIES: 8 | - Criollo (~> 0.5) 9 | - Sparkle 10 | 11 | SPEC REPOS: 12 | https://github.com/CocoaPods/Specs.git: 13 | - CocoaAsyncSocket 14 | - Criollo 15 | - Sparkle 16 | 17 | SPEC CHECKSUMS: 18 | CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 19 | Criollo: 617173837c296ca4248b0b058f36ce9b91e5c25b 20 | Sparkle: 55b1a87ba69d56913375a281546b7c82dec95bb0 21 | 22 | PODFILE CHECKSUM: bc9d5270465959491452d93b0cf4a7fcfb0fa41c 23 | 24 | COCOAPODS: 1.9.1 25 | -------------------------------------------------------------------------------- /Shelley/WelcomePopover.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SpotifyNotRunningViewController.swift 3 | // Spotish 4 | // 5 | // Created by Tyler Hall on 3/24/20. 6 | // Copyright © 2020 Your Company. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class WelcomePopover: NSViewController { 12 | 13 | var shouldDismiss: (() -> ())? 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | } 18 | 19 | @IBAction func openPrefs(_ sender: AnyObject?) { 20 | if let ad = NSApp.delegate as? AppDelegate { 21 | ad.showPrefs(sender) 22 | } 23 | shouldDismiss?() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Shelley/AboutWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AboutWindowController.swift 3 | // CommandQ 4 | // 5 | // Created by Tyler Hall on 6/21/19. 6 | // Copyright © 2019 Click On Tyler. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class AboutWindowController: NSWindowController { 12 | 13 | @IBOutlet weak var versionTextField: NSTextField! 14 | 15 | override func windowDidLoad() { 16 | super.windowDidLoad() 17 | 18 | window?.isMovableByWindowBackground = true 19 | window?.tabbingMode = .disallowed 20 | 21 | if let versionStr = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") { 22 | versionTextField.stringValue = "Version \(versionStr)" 23 | #if MAS 24 | versionTextField.stringValue = versionTextField.stringValue + " Mac App Store" 25 | #endif 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Shelley/PrefsWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrefsWindowController.swift 3 | // Jigsaw 4 | // 5 | // Created by Tyler Hall on 8/2/20. 6 | // Copyright © 2020 Tyler Hall. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class PrefsWindowController: NSWindowController { 12 | 13 | @IBOutlet weak var pathControl: NSPathControl! 14 | 15 | override func windowDidLoad() { 16 | super.windowDidLoad() 17 | pathControl.allowedTypes = ["public.folder"] 18 | updateUI() 19 | } 20 | 21 | func updateUI() { 22 | pathControl.url = Constants.scriptFolderURL 23 | } 24 | 25 | @IBAction func coffee(_ sender: AnyObject?) { 26 | NSWorkspace.shared.open(URL(string: "https://www.buymeacoffee.com/tylerhall")!) 27 | } 28 | 29 | @IBAction func chooseScriptFolder(_ sender: AnyObject?) { 30 | Constants.scriptFolderURL = pathControl.url 31 | updateUI() 32 | } 33 | 34 | @IBAction func openHelp(_ sender: AnyObject?) { 35 | NSWorkspace.shared.open(URL(string: "https://github.com/tylerhall/Shelley")!) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This software is licensed under the [MIT License](https://opensource.org/licenses/MIT). 2 | 3 | Copyright 2020 Tyler Hall. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Shelley/TaskRunner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaskRunner.swift 3 | // Shelley 4 | // 5 | // Created by Tyler Hall on 8/26/20. 6 | // Copyright © 2020 Tyler Hall. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class TaskRunner { 12 | 13 | var scriptURL: URL 14 | 15 | let uuid = UUID().uuidString 16 | 17 | init?(scriptName: String) { 18 | guard let url = Constants.scriptFolderURL?.appendingPathComponent(scriptName).appendingPathExtension("sh") else { return nil } 19 | if FileManager.default.isExecutableFile(atPath: url.path) { 20 | scriptURL = url 21 | } else { 22 | return nil 23 | } 24 | } 25 | 26 | func execute(_ completion: (() -> ())? = nil) { 27 | let sh = Process() 28 | sh.launchPath = scriptURL.path 29 | 30 | DispatchQueue.global(qos: .userInitiated).async { 31 | sh.launch() 32 | sh.waitUntilExit() 33 | completion?() 34 | } 35 | } 36 | } 37 | 38 | extension TaskRunner: Equatable { 39 | static func == (lhs: TaskRunner, rhs: TaskRunner) -> Bool { 40 | return lhs.uuid == rhs.uuid 41 | } 42 | } 43 | 44 | extension TaskRunner: Hashable { 45 | func hash(into hasher: inout Hasher) { 46 | hasher.combine(uuid) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Shelley/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0.0 21 | CFBundleVersion 22 | 2 23 | LSApplicationCategoryType 24 | public.app-category.utilities 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | LSUIElement 28 | 29 | NSHumanReadableCopyright 30 | Copyright © 2020 Tyler Hall. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | NSSupportsAutomaticTermination 36 | 37 | NSSupportsSuddenTermination 38 | 39 | SUFeedURL 40 | https://shine.clickontyler.com/appcast.php?id=53 41 | 42 | 43 | -------------------------------------------------------------------------------- /Shelley/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // Shelley 4 | // 5 | // Created by Tyler Hall on 8/26/20. 6 | // Copyright © 2020 Tyler Hall. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Constants { 12 | 13 | static let kLaunchCount = "kLaunchCount" 14 | 15 | static var scriptFolderURL: URL? { 16 | get { 17 | if let url = UserDefaults.standard.url(forKey: "scriptFolderURL") { 18 | return url 19 | } 20 | return URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Shelley") 21 | } 22 | set { 23 | UserDefaults.standard.set(newValue, forKey: "scriptFolderURL") 24 | UserDefaults.standard.synchronize() 25 | } 26 | } 27 | 28 | static var key: String? { 29 | guard let scriptFolderURL = scriptFolderURL else { return nil } 30 | if FileManager.default.fileExists(atPath: scriptFolderURL.path) { 31 | let keyURL = scriptFolderURL.appendingPathComponent("key").appendingPathExtension("txt") 32 | if FileManager.default.fileExists(atPath: keyURL.path) { 33 | return try? String(contentsOf: keyURL) 34 | } else { 35 | let key = UUID().uuidString 36 | do { 37 | try key.write(to: keyURL, atomically: true, encoding: .utf8) 38 | return key 39 | } catch { 40 | return nil 41 | } 42 | } 43 | } else { 44 | return nil 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Shelley/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon-16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon-16@2x.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon-32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon-32@2x.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon-128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon-128@2x.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon-256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon-256@2x.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon-512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "icon-512@2x.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | Packages/ 39 | Package.pins 40 | Package.resolved 41 | .build/ 42 | .swiftpm 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots/**/*.png 69 | fastlane/test_output 70 | 71 | .DS_Store 72 | -------------------------------------------------------------------------------- /Shelley/MenuBarStatusItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuBarStatusItem.swift 3 | // Ears 4 | // 5 | // Created by Tyler Hall on 3/14/20. 6 | // Copyright © 2020 Your Company. All rights reserved. 7 | // 8 | 9 | import AppKit 10 | 11 | class MenuBarStatusItem { 12 | 13 | var statusItem: NSStatusItem? 14 | 15 | var clicked: (() -> ())? 16 | var controlClicked: (() -> ())? 17 | 18 | init() { 19 | installMenuItem() 20 | } 21 | 22 | func installMenuItem() { 23 | if statusItem == nil { 24 | statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) 25 | statusItem?.button?.target = self 26 | statusItem?.button?.action = #selector(statusItemClicked(_:)) 27 | statusItem?.button?.sendAction(on: [.leftMouseDown, .rightMouseDown]) 28 | } 29 | } 30 | 31 | func removeStatusItem() { 32 | if let statusItem = statusItem { 33 | NSStatusBar.system.removeStatusItem(statusItem) 34 | } 35 | } 36 | 37 | func setTitle(_ title: String?) { 38 | statusItem?.button?.title = title ?? "" 39 | } 40 | 41 | func setImage(_ image: NSImage?) { 42 | statusItem?.button?.image = image 43 | } 44 | 45 | func setImageNamed(_ imageName: String?) { 46 | if let imageName = imageName { 47 | let image = NSImage(named: imageName) 48 | setImage(image) 49 | } else { 50 | setImage(nil) 51 | } 52 | } 53 | 54 | // Note: Setting a popup menu will break the click handlers (for now). 55 | func setMenu(_ menu: NSMenu?) { 56 | statusItem?.menu = menu 57 | } 58 | 59 | func show() { 60 | statusItem?.isVisible = true 61 | } 62 | 63 | func hide() { 64 | statusItem?.isVisible = false 65 | } 66 | 67 | @objc @IBAction func statusItemClicked(_ sender: AnyObject?) { 68 | if let event = NSApp.currentEvent, event.isRightClick { 69 | controlClicked?() 70 | } else { 71 | clicked?() 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Shelley/Server.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Server.swift 3 | // Shelley 4 | // 5 | // Created by Tyler Hall on 8/26/20. 6 | // Copyright © 2020 Tyler Hall. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Server { 12 | 13 | static let shared = Server() 14 | 15 | let HTTPServer = CRHTTPServer() 16 | 17 | var taskRunners = Set() 18 | 19 | func start() { 20 | HTTPServer.options(nil) { (request, response, next) in 21 | response.setAllHTTPHeaderFields(["Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "POST, OPTIONS"]) 22 | response.send("") 23 | } 24 | 25 | HTTPServer.get(nil) { [weak self] (request, response, next) in 26 | guard let self = self else { return } 27 | 28 | let components = request.url.pathComponents 29 | guard components.count >= 3 else { 30 | response.send("Invalid command: " + UUID().uuidString) 31 | return 32 | } 33 | 34 | guard self.keyIsValid(request: request) else { 35 | response.send("Invalid key: " + UUID().uuidString) 36 | return 37 | } 38 | 39 | let command = components[1].lowercased() 40 | let scriptName = components[2] 41 | 42 | if !["run", "wait"].contains(command) { 43 | response.send("Invalid command: " + UUID().uuidString) 44 | return 45 | } 46 | 47 | if scriptName.count > 0, let runner = TaskRunner(scriptName: scriptName) { 48 | if command == "run" { 49 | runner.execute() 50 | response.send("OK: " + UUID().uuidString) 51 | } else if command == "wait" { 52 | runner.execute { 53 | response.send("OK: " + UUID().uuidString) 54 | } 55 | } 56 | } else { 57 | response.send("Script does not exist: " + UUID().uuidString) 58 | } 59 | } 60 | 61 | HTTPServer.startListening(nil, portNumber: UInt(9876)) 62 | } 63 | 64 | func keyIsValid(request: CRRequest) -> Bool { 65 | if let headerKey = request.allHTTPHeaderFields["key"] { 66 | return headerKey == Constants.key 67 | } 68 | return request.url.lastPathComponent == Constants.key 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Shelley/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Shelley 4 | // 5 | // Created by Tyler Hall on 8/26/20. 6 | // Copyright © 2020 Tyler Hall. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | @IBOutlet weak var statusBarMenu: NSMenu! 15 | 16 | lazy var prefsWindowController: PrefsWindowController = { PrefsWindowController(windowNibName: String(describing: PrefsWindowController.self)) }() 17 | lazy var aboutWindowController: AboutWindowController = { AboutWindowController(windowNibName: String(describing: AboutWindowController.self)) }() 18 | 19 | let statusItem = MenuBarStatusItem() 20 | let statusItemPopover = NSPopover() 21 | lazy var welcomeViewController: WelcomePopover = { WelcomePopover(nibName: String(describing: WelcomePopover.self), bundle: nil) }() 22 | 23 | func applicationDidFinishLaunching(_ aNotification: Notification) { 24 | registerDefaults() 25 | 26 | statusItem.setImageNamed("Menubar") 27 | statusItem.setMenu(statusBarMenu) 28 | 29 | incrementLaunchCount() 30 | if launchCount() == 1 { 31 | showWelcomePopover(nil) 32 | } 33 | 34 | Server.shared.start() 35 | 36 | SUUpdater.shared()?.checkForUpdatesInBackground() 37 | } 38 | 39 | func registerDefaults() { 40 | if let defaultsPath = Bundle.main.path(forResource: "Defaults", ofType: "plist") { 41 | if let defaults = NSDictionary(contentsOfFile: defaultsPath) as? [String: Any] { 42 | UserDefaults.standard.register(defaults: defaults) 43 | } 44 | } 45 | } 46 | 47 | func incrementLaunchCount() { 48 | let launchInt = launchCount() + 1 49 | 50 | let launchNumber = NSNumber(value: launchInt) 51 | UserDefaults.standard.setValue(launchNumber, forKey: Constants.kLaunchCount) 52 | UserDefaults.standard.synchronize() 53 | } 54 | 55 | func launchCount() -> Int { 56 | if let launchNumber = UserDefaults.standard.value(forKey: Constants.kLaunchCount) as? NSNumber { 57 | return launchNumber.intValue 58 | } else { 59 | return 0 60 | } 61 | } 62 | } 63 | 64 | extension AppDelegate { 65 | 66 | @IBAction func showPrefs(_ sender: AnyObject?) { 67 | prefsWindowController.showWindow(sender) 68 | prefsWindowController.window?.makeKeyAndOrderFront(sender) 69 | NSApp.activate(ignoringOtherApps: true) 70 | } 71 | 72 | @IBAction func showAbout(_ sender: AnyObject?) { 73 | aboutWindowController.showWindow(nil) 74 | aboutWindowController.window?.makeKeyAndOrderFront(sender) 75 | aboutWindowController.window?.center() 76 | NSApp.activate(ignoringOtherApps: true) 77 | } 78 | 79 | @IBAction func checkForUpdates(_ sender: AnyObject?) { 80 | SUUpdater.shared()?.checkForUpdates(nil) 81 | } 82 | 83 | @IBAction func quit(_ sender: AnyObject?) { 84 | NSApp.terminate(nil) 85 | } 86 | 87 | @IBAction func showWelcomePopover(_ sender: AnyObject?) { 88 | statusItemPopover.behavior = .applicationDefined 89 | statusItemPopover.contentViewController = welcomeViewController 90 | statusItemPopover.show(relativeTo: .zero, of: (statusItem.statusItem?.button)!, preferredEdge: .minY) 91 | welcomeViewController.shouldDismiss = { [weak self] in 92 | self?.statusItemPopover.close() 93 | } 94 | } 95 | 96 | @IBAction func otherApps(_ sender: AnyObject?) { 97 | NSWorkspace.shared.open(URL(string: "https://clickontyler.com")!) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Shelley/AboutWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Shelley/WelcomePopover.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Shelley/PrefsWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 60 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Shelley.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C6512D3C24F727B800EB2AB7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6512D3B24F727B800EB2AB7 /* AppDelegate.swift */; }; 11 | C6512D3E24F727BA00EB2AB7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6512D3D24F727BA00EB2AB7 /* Assets.xcassets */; }; 12 | C6512D4124F727BA00EB2AB7 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C6512D3F24F727BA00EB2AB7 /* MainMenu.xib */; }; 13 | C6512D4B24F727EC00EB2AB7 /* WelcomePopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6512D4924F727EC00EB2AB7 /* WelcomePopover.swift */; }; 14 | C6512D4C24F727EC00EB2AB7 /* WelcomePopover.xib in Resources */ = {isa = PBXBuildFile; fileRef = C6512D4A24F727EC00EB2AB7 /* WelcomePopover.xib */; }; 15 | C6512D4F24F727F700EB2AB7 /* AboutWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C6512D4D24F727F700EB2AB7 /* AboutWindowController.xib */; }; 16 | C6512D5024F727F700EB2AB7 /* AboutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6512D4E24F727F700EB2AB7 /* AboutWindowController.swift */; }; 17 | C6512D5324F727FE00EB2AB7 /* PrefsWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6512D5124F727FE00EB2AB7 /* PrefsWindowController.swift */; }; 18 | C6512D5424F727FE00EB2AB7 /* PrefsWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C6512D5224F727FE00EB2AB7 /* PrefsWindowController.xib */; }; 19 | C6512D5624F7280C00EB2AB7 /* MenuBarStatusItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6512D5524F7280C00EB2AB7 /* MenuBarStatusItem.swift */; }; 20 | C6512D5824F7284D00EB2AB7 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6512D5724F7284D00EB2AB7 /* Extensions.swift */; }; 21 | C6512D5A24F72CD700EB2AB7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6512D5924F72CD700EB2AB7 /* Constants.swift */; }; 22 | C6512D6424F736B500EB2AB7 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6512D6324F736B500EB2AB7 /* Server.swift */; }; 23 | C65236DF24F7499C008A4577 /* TaskRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65236DE24F7499C008A4577 /* TaskRunner.swift */; }; 24 | C65236E124F74F6B008A4577 /* Defaults.plist in Resources */ = {isa = PBXBuildFile; fileRef = C65236E024F74F6B008A4577 /* Defaults.plist */; }; 25 | F9B850C273B565E14F2B0B1B /* libPods-Shelley.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CBA1B28D70E05972D29E051 /* libPods-Shelley.a */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXCopyFilesBuildPhase section */ 29 | C6512D6124F72FA100EB2AB7 /* Frameworks */ = { 30 | isa = PBXCopyFilesBuildPhase; 31 | buildActionMask = 2147483647; 32 | dstPath = ""; 33 | dstSubfolderSpec = 10; 34 | files = ( 35 | ); 36 | name = Frameworks; 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXCopyFilesBuildPhase section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 1CBA1B28D70E05972D29E051 /* libPods-Shelley.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Shelley.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 6D6F69593073EA64FF080D8B /* Pods-RequestBar.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RequestBar.debug.xcconfig"; path = "Target Support Files/Pods-RequestBar/Pods-RequestBar.debug.xcconfig"; sourceTree = ""; }; 44 | 9B4470F070F997A74B879D74 /* Pods-RequestBar.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RequestBar.release.xcconfig"; path = "Target Support Files/Pods-RequestBar/Pods-RequestBar.release.xcconfig"; sourceTree = ""; }; 45 | 9FC372CFF153D8D3E7222F86 /* Pods-Shelley.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Shelley.release.xcconfig"; path = "Target Support Files/Pods-Shelley/Pods-Shelley.release.xcconfig"; sourceTree = ""; }; 46 | B3EF497A753691E0BB27D6C8 /* Pods-Shelley.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Shelley.debug.xcconfig"; path = "Target Support Files/Pods-Shelley/Pods-Shelley.debug.xcconfig"; sourceTree = ""; }; 47 | C6512D3824F727B800EB2AB7 /* Shelley.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Shelley.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | C6512D3B24F727B800EB2AB7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 49 | C6512D3D24F727BA00EB2AB7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | C6512D4024F727BA00EB2AB7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 51 | C6512D4224F727BA00EB2AB7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | C6512D4924F727EC00EB2AB7 /* WelcomePopover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomePopover.swift; sourceTree = ""; }; 53 | C6512D4A24F727EC00EB2AB7 /* WelcomePopover.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WelcomePopover.xib; sourceTree = ""; }; 54 | C6512D4D24F727F700EB2AB7 /* AboutWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AboutWindowController.xib; sourceTree = ""; }; 55 | C6512D4E24F727F700EB2AB7 /* AboutWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutWindowController.swift; sourceTree = ""; }; 56 | C6512D5124F727FE00EB2AB7 /* PrefsWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefsWindowController.swift; sourceTree = ""; }; 57 | C6512D5224F727FE00EB2AB7 /* PrefsWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PrefsWindowController.xib; sourceTree = ""; }; 58 | C6512D5524F7280C00EB2AB7 /* MenuBarStatusItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuBarStatusItem.swift; sourceTree = ""; }; 59 | C6512D5724F7284D00EB2AB7 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 60 | C6512D5924F72CD700EB2AB7 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 61 | C6512D5D24F72F6800EB2AB7 /* Shelley-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Shelley-Bridging-Header.h"; sourceTree = ""; }; 62 | C6512D6324F736B500EB2AB7 /* Server.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Server.swift; sourceTree = ""; }; 63 | C65236DE24F7499C008A4577 /* TaskRunner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskRunner.swift; sourceTree = ""; }; 64 | C65236E024F74F6B008A4577 /* Defaults.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Defaults.plist; sourceTree = ""; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | C6512D3524F727B800EB2AB7 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | F9B850C273B565E14F2B0B1B /* libPods-Shelley.a in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | 2304FC7AB1D6F88283EF867C /* Pods */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 6D6F69593073EA64FF080D8B /* Pods-RequestBar.debug.xcconfig */, 83 | 9B4470F070F997A74B879D74 /* Pods-RequestBar.release.xcconfig */, 84 | B3EF497A753691E0BB27D6C8 /* Pods-Shelley.debug.xcconfig */, 85 | 9FC372CFF153D8D3E7222F86 /* Pods-Shelley.release.xcconfig */, 86 | ); 87 | path = Pods; 88 | sourceTree = ""; 89 | }; 90 | 6610344A598B30E0E8BB6055 /* Frameworks */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 1CBA1B28D70E05972D29E051 /* libPods-Shelley.a */, 94 | ); 95 | name = Frameworks; 96 | sourceTree = ""; 97 | }; 98 | C6512D2F24F727B800EB2AB7 = { 99 | isa = PBXGroup; 100 | children = ( 101 | C6512D3A24F727B800EB2AB7 /* Shelley */, 102 | C6512D3924F727B800EB2AB7 /* Products */, 103 | 2304FC7AB1D6F88283EF867C /* Pods */, 104 | 6610344A598B30E0E8BB6055 /* Frameworks */, 105 | ); 106 | sourceTree = ""; 107 | }; 108 | C6512D3924F727B800EB2AB7 /* Products */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | C6512D3824F727B800EB2AB7 /* Shelley.app */, 112 | ); 113 | name = Products; 114 | sourceTree = ""; 115 | }; 116 | C6512D3A24F727B800EB2AB7 /* Shelley */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | C6512D3B24F727B800EB2AB7 /* AppDelegate.swift */, 120 | C6512D6324F736B500EB2AB7 /* Server.swift */, 121 | C6512D4924F727EC00EB2AB7 /* WelcomePopover.swift */, 122 | C6512D4A24F727EC00EB2AB7 /* WelcomePopover.xib */, 123 | C6512D4E24F727F700EB2AB7 /* AboutWindowController.swift */, 124 | C6512D4D24F727F700EB2AB7 /* AboutWindowController.xib */, 125 | C6512D5124F727FE00EB2AB7 /* PrefsWindowController.swift */, 126 | C6512D5224F727FE00EB2AB7 /* PrefsWindowController.xib */, 127 | C6512D5524F7280C00EB2AB7 /* MenuBarStatusItem.swift */, 128 | C6512D5724F7284D00EB2AB7 /* Extensions.swift */, 129 | C6512D3D24F727BA00EB2AB7 /* Assets.xcassets */, 130 | C6512D3F24F727BA00EB2AB7 /* MainMenu.xib */, 131 | C6512D4224F727BA00EB2AB7 /* Info.plist */, 132 | C6512D5924F72CD700EB2AB7 /* Constants.swift */, 133 | C6512D5D24F72F6800EB2AB7 /* Shelley-Bridging-Header.h */, 134 | C65236DE24F7499C008A4577 /* TaskRunner.swift */, 135 | C65236E024F74F6B008A4577 /* Defaults.plist */, 136 | ); 137 | path = Shelley; 138 | sourceTree = ""; 139 | }; 140 | /* End PBXGroup section */ 141 | 142 | /* Begin PBXNativeTarget section */ 143 | C6512D3724F727B800EB2AB7 /* Shelley */ = { 144 | isa = PBXNativeTarget; 145 | buildConfigurationList = C6512D4624F727BA00EB2AB7 /* Build configuration list for PBXNativeTarget "Shelley" */; 146 | buildPhases = ( 147 | CBA8E01ECB1A010B359295BD /* [CP] Check Pods Manifest.lock */, 148 | C6512D3424F727B800EB2AB7 /* Sources */, 149 | C6512D3524F727B800EB2AB7 /* Frameworks */, 150 | C6512D3624F727B800EB2AB7 /* Resources */, 151 | C6512D6124F72FA100EB2AB7 /* Frameworks */, 152 | 3CA505867D691D2055FBBAE8 /* [CP] Embed Pods Frameworks */, 153 | ); 154 | buildRules = ( 155 | ); 156 | dependencies = ( 157 | ); 158 | name = Shelley; 159 | productName = RequestBar; 160 | productReference = C6512D3824F727B800EB2AB7 /* Shelley.app */; 161 | productType = "com.apple.product-type.application"; 162 | }; 163 | /* End PBXNativeTarget section */ 164 | 165 | /* Begin PBXProject section */ 166 | C6512D3024F727B800EB2AB7 /* Project object */ = { 167 | isa = PBXProject; 168 | attributes = { 169 | LastSwiftUpdateCheck = 1160; 170 | LastUpgradeCheck = 1160; 171 | ORGANIZATIONNAME = "Tyler Hall"; 172 | TargetAttributes = { 173 | C6512D3724F727B800EB2AB7 = { 174 | CreatedOnToolsVersion = 11.6; 175 | LastSwiftMigration = 1160; 176 | }; 177 | }; 178 | }; 179 | buildConfigurationList = C6512D3324F727B800EB2AB7 /* Build configuration list for PBXProject "Shelley" */; 180 | compatibilityVersion = "Xcode 9.3"; 181 | developmentRegion = en; 182 | hasScannedForEncodings = 0; 183 | knownRegions = ( 184 | en, 185 | Base, 186 | ); 187 | mainGroup = C6512D2F24F727B800EB2AB7; 188 | productRefGroup = C6512D3924F727B800EB2AB7 /* Products */; 189 | projectDirPath = ""; 190 | projectRoot = ""; 191 | targets = ( 192 | C6512D3724F727B800EB2AB7 /* Shelley */, 193 | ); 194 | }; 195 | /* End PBXProject section */ 196 | 197 | /* Begin PBXResourcesBuildPhase section */ 198 | C6512D3624F727B800EB2AB7 /* Resources */ = { 199 | isa = PBXResourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | C6512D4C24F727EC00EB2AB7 /* WelcomePopover.xib in Resources */, 203 | C6512D4F24F727F700EB2AB7 /* AboutWindowController.xib in Resources */, 204 | C65236E124F74F6B008A4577 /* Defaults.plist in Resources */, 205 | C6512D5424F727FE00EB2AB7 /* PrefsWindowController.xib in Resources */, 206 | C6512D3E24F727BA00EB2AB7 /* Assets.xcassets in Resources */, 207 | C6512D4124F727BA00EB2AB7 /* MainMenu.xib in Resources */, 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXResourcesBuildPhase section */ 212 | 213 | /* Begin PBXShellScriptBuildPhase section */ 214 | 3CA505867D691D2055FBBAE8 /* [CP] Embed Pods Frameworks */ = { 215 | isa = PBXShellScriptBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | inputFileListPaths = ( 220 | "${PODS_ROOT}/Target Support Files/Pods-Shelley/Pods-Shelley-frameworks-${CONFIGURATION}-input-files.xcfilelist", 221 | ); 222 | name = "[CP] Embed Pods Frameworks"; 223 | outputFileListPaths = ( 224 | "${PODS_ROOT}/Target Support Files/Pods-Shelley/Pods-Shelley-frameworks-${CONFIGURATION}-output-files.xcfilelist", 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | shellPath = /bin/sh; 228 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Shelley/Pods-Shelley-frameworks.sh\"\n"; 229 | showEnvVarsInLog = 0; 230 | }; 231 | CBA8E01ECB1A010B359295BD /* [CP] Check Pods Manifest.lock */ = { 232 | isa = PBXShellScriptBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | ); 236 | inputFileListPaths = ( 237 | ); 238 | inputPaths = ( 239 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 240 | "${PODS_ROOT}/Manifest.lock", 241 | ); 242 | name = "[CP] Check Pods Manifest.lock"; 243 | outputFileListPaths = ( 244 | ); 245 | outputPaths = ( 246 | "$(DERIVED_FILE_DIR)/Pods-Shelley-checkManifestLockResult.txt", 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | shellPath = /bin/sh; 250 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 251 | showEnvVarsInLog = 0; 252 | }; 253 | /* End PBXShellScriptBuildPhase section */ 254 | 255 | /* Begin PBXSourcesBuildPhase section */ 256 | C6512D3424F727B800EB2AB7 /* Sources */ = { 257 | isa = PBXSourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | C6512D5624F7280C00EB2AB7 /* MenuBarStatusItem.swift in Sources */, 261 | C6512D5824F7284D00EB2AB7 /* Extensions.swift in Sources */, 262 | C65236DF24F7499C008A4577 /* TaskRunner.swift in Sources */, 263 | C6512D5024F727F700EB2AB7 /* AboutWindowController.swift in Sources */, 264 | C6512D4B24F727EC00EB2AB7 /* WelcomePopover.swift in Sources */, 265 | C6512D5A24F72CD700EB2AB7 /* Constants.swift in Sources */, 266 | C6512D5324F727FE00EB2AB7 /* PrefsWindowController.swift in Sources */, 267 | C6512D6424F736B500EB2AB7 /* Server.swift in Sources */, 268 | C6512D3C24F727B800EB2AB7 /* AppDelegate.swift in Sources */, 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | /* End PBXSourcesBuildPhase section */ 273 | 274 | /* Begin PBXVariantGroup section */ 275 | C6512D3F24F727BA00EB2AB7 /* MainMenu.xib */ = { 276 | isa = PBXVariantGroup; 277 | children = ( 278 | C6512D4024F727BA00EB2AB7 /* Base */, 279 | ); 280 | name = MainMenu.xib; 281 | sourceTree = ""; 282 | }; 283 | /* End PBXVariantGroup section */ 284 | 285 | /* Begin XCBuildConfiguration section */ 286 | C6512D4424F727BA00EB2AB7 /* Debug */ = { 287 | isa = XCBuildConfiguration; 288 | buildSettings = { 289 | ALWAYS_SEARCH_USER_PATHS = NO; 290 | CLANG_ANALYZER_NONNULL = YES; 291 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 292 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 293 | CLANG_CXX_LIBRARY = "libc++"; 294 | CLANG_ENABLE_MODULES = YES; 295 | CLANG_ENABLE_OBJC_ARC = YES; 296 | CLANG_ENABLE_OBJC_WEAK = YES; 297 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 298 | CLANG_WARN_BOOL_CONVERSION = YES; 299 | CLANG_WARN_COMMA = YES; 300 | CLANG_WARN_CONSTANT_CONVERSION = YES; 301 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 302 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 303 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 304 | CLANG_WARN_EMPTY_BODY = YES; 305 | CLANG_WARN_ENUM_CONVERSION = YES; 306 | CLANG_WARN_INFINITE_RECURSION = YES; 307 | CLANG_WARN_INT_CONVERSION = YES; 308 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 309 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 310 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 311 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 312 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 313 | CLANG_WARN_STRICT_PROTOTYPES = YES; 314 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 315 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 316 | CLANG_WARN_UNREACHABLE_CODE = YES; 317 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 318 | COPY_PHASE_STRIP = NO; 319 | DEBUG_INFORMATION_FORMAT = dwarf; 320 | ENABLE_STRICT_OBJC_MSGSEND = YES; 321 | ENABLE_TESTABILITY = YES; 322 | GCC_C_LANGUAGE_STANDARD = gnu11; 323 | GCC_DYNAMIC_NO_PIC = NO; 324 | GCC_NO_COMMON_BLOCKS = YES; 325 | GCC_OPTIMIZATION_LEVEL = 0; 326 | GCC_PREPROCESSOR_DEFINITIONS = ( 327 | "DEBUG=1", 328 | "$(inherited)", 329 | ); 330 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 331 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 332 | GCC_WARN_UNDECLARED_SELECTOR = YES; 333 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 334 | GCC_WARN_UNUSED_FUNCTION = YES; 335 | GCC_WARN_UNUSED_VARIABLE = YES; 336 | MACOSX_DEPLOYMENT_TARGET = 10.15; 337 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 338 | MTL_FAST_MATH = YES; 339 | ONLY_ACTIVE_ARCH = YES; 340 | SDKROOT = macosx; 341 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 342 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 343 | }; 344 | name = Debug; 345 | }; 346 | C6512D4524F727BA00EB2AB7 /* Release */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | ALWAYS_SEARCH_USER_PATHS = NO; 350 | CLANG_ANALYZER_NONNULL = YES; 351 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 352 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 353 | CLANG_CXX_LIBRARY = "libc++"; 354 | CLANG_ENABLE_MODULES = YES; 355 | CLANG_ENABLE_OBJC_ARC = YES; 356 | CLANG_ENABLE_OBJC_WEAK = YES; 357 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 358 | CLANG_WARN_BOOL_CONVERSION = YES; 359 | CLANG_WARN_COMMA = YES; 360 | CLANG_WARN_CONSTANT_CONVERSION = YES; 361 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 362 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 363 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 364 | CLANG_WARN_EMPTY_BODY = YES; 365 | CLANG_WARN_ENUM_CONVERSION = YES; 366 | CLANG_WARN_INFINITE_RECURSION = YES; 367 | CLANG_WARN_INT_CONVERSION = YES; 368 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 369 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 370 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 371 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 372 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 373 | CLANG_WARN_STRICT_PROTOTYPES = YES; 374 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 375 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 376 | CLANG_WARN_UNREACHABLE_CODE = YES; 377 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 378 | COPY_PHASE_STRIP = NO; 379 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 380 | ENABLE_NS_ASSERTIONS = NO; 381 | ENABLE_STRICT_OBJC_MSGSEND = YES; 382 | GCC_C_LANGUAGE_STANDARD = gnu11; 383 | GCC_NO_COMMON_BLOCKS = YES; 384 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 385 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 386 | GCC_WARN_UNDECLARED_SELECTOR = YES; 387 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 388 | GCC_WARN_UNUSED_FUNCTION = YES; 389 | GCC_WARN_UNUSED_VARIABLE = YES; 390 | MACOSX_DEPLOYMENT_TARGET = 10.15; 391 | MTL_ENABLE_DEBUG_INFO = NO; 392 | MTL_FAST_MATH = YES; 393 | SDKROOT = macosx; 394 | SWIFT_COMPILATION_MODE = wholemodule; 395 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 396 | }; 397 | name = Release; 398 | }; 399 | C6512D4724F727BA00EB2AB7 /* Debug */ = { 400 | isa = XCBuildConfiguration; 401 | baseConfigurationReference = B3EF497A753691E0BB27D6C8 /* Pods-Shelley.debug.xcconfig */; 402 | buildSettings = { 403 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 404 | CLANG_ENABLE_MODULES = YES; 405 | CODE_SIGN_STYLE = Automatic; 406 | COMBINE_HIDPI_IMAGES = YES; 407 | CURRENT_PROJECT_VERSION = 2; 408 | DEVELOPMENT_TEAM = 3A6K89K388; 409 | ENABLE_HARDENED_RUNTIME = YES; 410 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 411 | INFOPLIST_FILE = Shelley/Info.plist; 412 | LD_RUNPATH_SEARCH_PATHS = ( 413 | "$(inherited)", 414 | "@executable_path/../Frameworks", 415 | ); 416 | PRODUCT_BUNDLE_IDENTIFIER = io.tyler.Shelley; 417 | PRODUCT_NAME = "$(TARGET_NAME)"; 418 | SWIFT_OBJC_BRIDGING_HEADER = "Shelley/Shelley-Bridging-Header.h"; 419 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 420 | SWIFT_VERSION = 5.0; 421 | VERSIONING_SYSTEM = "apple-generic"; 422 | }; 423 | name = Debug; 424 | }; 425 | C6512D4824F727BA00EB2AB7 /* Release */ = { 426 | isa = XCBuildConfiguration; 427 | baseConfigurationReference = 9FC372CFF153D8D3E7222F86 /* Pods-Shelley.release.xcconfig */; 428 | buildSettings = { 429 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 430 | CLANG_ENABLE_MODULES = YES; 431 | CODE_SIGN_STYLE = Automatic; 432 | COMBINE_HIDPI_IMAGES = YES; 433 | CURRENT_PROJECT_VERSION = 2; 434 | DEVELOPMENT_TEAM = 3A6K89K388; 435 | ENABLE_HARDENED_RUNTIME = YES; 436 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 437 | INFOPLIST_FILE = Shelley/Info.plist; 438 | LD_RUNPATH_SEARCH_PATHS = ( 439 | "$(inherited)", 440 | "@executable_path/../Frameworks", 441 | ); 442 | PRODUCT_BUNDLE_IDENTIFIER = io.tyler.Shelley; 443 | PRODUCT_NAME = "$(TARGET_NAME)"; 444 | SWIFT_OBJC_BRIDGING_HEADER = "Shelley/Shelley-Bridging-Header.h"; 445 | SWIFT_VERSION = 5.0; 446 | VERSIONING_SYSTEM = "apple-generic"; 447 | }; 448 | name = Release; 449 | }; 450 | /* End XCBuildConfiguration section */ 451 | 452 | /* Begin XCConfigurationList section */ 453 | C6512D3324F727B800EB2AB7 /* Build configuration list for PBXProject "Shelley" */ = { 454 | isa = XCConfigurationList; 455 | buildConfigurations = ( 456 | C6512D4424F727BA00EB2AB7 /* Debug */, 457 | C6512D4524F727BA00EB2AB7 /* Release */, 458 | ); 459 | defaultConfigurationIsVisible = 0; 460 | defaultConfigurationName = Release; 461 | }; 462 | C6512D4624F727BA00EB2AB7 /* Build configuration list for PBXNativeTarget "Shelley" */ = { 463 | isa = XCConfigurationList; 464 | buildConfigurations = ( 465 | C6512D4724F727BA00EB2AB7 /* Debug */, 466 | C6512D4824F727BA00EB2AB7 /* Release */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | defaultConfigurationName = Release; 470 | }; 471 | /* End XCConfigurationList section */ 472 | }; 473 | rootObject = C6512D3024F727B800EB2AB7 /* Project object */; 474 | } 475 | -------------------------------------------------------------------------------- /Shelley/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | Default 538 | 539 | 540 | 541 | 542 | 543 | 544 | Left to Right 545 | 546 | 547 | 548 | 549 | 550 | 551 | Right to Left 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | Default 563 | 564 | 565 | 566 | 567 | 568 | 569 | Left to Right 570 | 571 | 572 | 573 | 574 | 575 | 576 | Right to Left 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | --------------------------------------------------------------------------------