Feature: Add multi server proxy editor from ss-ng

This commit is contained in:
yicheng 2018-08-05 18:00:34 +08:00
parent 7d6745e2f0
commit 3f407a2c29
5 changed files with 837 additions and 2 deletions

View File

@ -13,6 +13,9 @@
492C4869210EE6B9004554A0 /* ApiRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 492C4868210EE6B9004554A0 /* ApiRequest.swift */; };
492C4871210EF62E004554A0 /* ClashConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 492C4870210EF62E004554A0 /* ClashConfig.swift */; };
4952C3BF2115C7CA004A4FA8 /* ProxyMenuItemFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4952C3BE2115C7CA004A4FA8 /* ProxyMenuItemFactory.swift */; };
4952C3CB2116E952004A4FA8 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4952C3C82116E952004A4FA8 /* PreferencesWindowController.swift */; };
4952C3CC2116E952004A4FA8 /* PreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4952C3CA2116E952004A4FA8 /* PreferencesWindowController.xib */; };
4952C3CE2116EA2E004A4FA8 /* ProxyServerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4952C3CD2116EA2E004A4FA8 /* ProxyServerModel.swift */; };
495340B020DE5F7200B0D3FF /* StatusItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 495340AF20DE5F7200B0D3FF /* StatusItemView.xib */; };
495340B320DE68C300B0D3FF /* StatusItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 495340B220DE68C300B0D3FF /* StatusItemView.swift */; };
495A44BF20D2660A00888A0A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 495A44BE20D2660A00888A0A /* AppDelegate.swift */; };
@ -75,6 +78,9 @@
492C4868210EE6B9004554A0 /* ApiRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiRequest.swift; sourceTree = "<group>"; };
492C4870210EF62E004554A0 /* ClashConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClashConfig.swift; sourceTree = "<group>"; };
4952C3BE2115C7CA004A4FA8 /* ProxyMenuItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyMenuItemFactory.swift; sourceTree = "<group>"; };
4952C3C82116E952004A4FA8 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
4952C3CA2116E952004A4FA8 /* PreferencesWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreferencesWindowController.xib; sourceTree = "<group>"; };
4952C3CD2116EA2E004A4FA8 /* ProxyServerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyServerModel.swift; sourceTree = "<group>"; };
495340AF20DE5F7200B0D3FF /* StatusItemView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StatusItemView.xib; sourceTree = "<group>"; };
495340B220DE68C300B0D3FF /* StatusItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusItemView.swift; sourceTree = "<group>"; };
495A44BC20D2660A00888A0A /* ClashXLaunchHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ClashXLaunchHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -152,6 +158,7 @@
isa = PBXGroup;
children = (
492C4870210EF62E004554A0 /* ClashConfig.swift */,
4952C3CD2116EA2E004A4FA8 /* ProxyServerModel.swift */,
);
path = Models;
sourceTree = "<group>";
@ -170,6 +177,8 @@
4989F98520D0AA300001E564 /* ViewControllers */ = {
isa = PBXGroup;
children = (
4952C3C82116E952004A4FA8 /* PreferencesWindowController.swift */,
4952C3CA2116E952004A4FA8 /* PreferencesWindowController.xib */,
4989F98920D0AD800001E564 /* SampleConfigViewController.swift */,
495340AF20DE5F7200B0D3FF /* StatusItemView.xib */,
495340B220DE68C300B0D3FF /* StatusItemView.swift */,
@ -432,6 +441,7 @@
49CF3B5F20CE80D2001EBF94 /* install_proxy_helper.sh in Resources */,
49CF3B4020CD7845001EBF94 /* menu_icon_disabled@2x.png in Resources */,
49CF3B3F20CD7845001EBF94 /* menu_icon.png in Resources */,
4952C3CC2116E952004A4FA8 /* PreferencesWindowController.xib in Resources */,
4989F98420D02D200001E564 /* Country.mmdb in Resources */,
497F0DF320DE2FE50077AD41 /* Icon.icns in Resources */,
492C4865210EC9E4004554A0 /* ProxyConfig in Resources */,
@ -525,11 +535,13 @@
495340B320DE68C300B0D3FF /* StatusItemView.swift in Sources */,
495A44D320D267D000888A0A /* LaunchAtLogin.swift in Sources */,
49CF3B2120CD7463001EBF94 /* AppDelegate.swift in Sources */,
4952C3CB2116E952004A4FA8 /* PreferencesWindowController.swift in Sources */,
4913C82321157D0200F6B87C /* Notification.swift in Sources */,
492C4871210EF62E004554A0 /* ClashConfig.swift in Sources */,
492C4869210EE6B9004554A0 /* ApiRequest.swift in Sources */,
49CF3B6520CEE06C001EBF94 /* ConfigManager.swift in Sources */,
4952C3BF2115C7CA004A4FA8 /* ProxyMenuItemFactory.swift in Sources */,
4952C3CE2116EA2E004A4FA8 /* ProxyServerModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -189,8 +189,10 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var genConfigWindow:NSWindowController?=nil
@IBAction func actionGenConfig(_ sender: Any) {
let ctrl = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "sampleConfigGenerator")) as! NSWindowController
// let ctrl = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
// .instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "sampleConfigGenerator")) as! NSWindowController
let ctrl = PreferencesWindowController(windowNibName: NSNib.Name(rawValue: "PreferencesWindowController"))
genConfigWindow?.close()
genConfigWindow=ctrl

View File

@ -0,0 +1,67 @@
//
// ProxyServerModel.swift
// ClashX
//
// Created by CYC on 2018/8/5.
// Copyright © 2018 west2online. All rights reserved.
//
import Cocoa
class ProxyServerModel: NSObject, Codable {
@objc dynamic var serverHost:String = ""
@objc dynamic var serverPort:String = ""
@objc dynamic var password:String = ""
@objc dynamic var method:String = "RC4-MD5"
@objc dynamic var remark:String = "Proxy"
func isValid() -> Bool {
func validateIpAddress(_ ipToValidate: String) -> Bool {
var sin = sockaddr_in()
var sin6 = sockaddr_in6()
if ipToValidate.withCString({ cstring in inet_pton(AF_INET6, cstring, &sin6.sin6_addr) }) == 1 {
// IPv6 peer.
return true
}
else if ipToValidate.withCString({ cstring in inet_pton(AF_INET, cstring, &sin.sin_addr) }) == 1 {
// IPv4 peer.
return true
}
return false;
}
func validateDomainName(_ value: String) -> Bool {
let validHostnameRegex = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$"
if (value.range(of: validHostnameRegex, options: .regularExpression) != nil) {
return true
} else {
return false
}
}
func validatePort(_ value: String) -> Bool {
if let port = Int(value) {
return port > 0 && port <= 65535
}
return false
}
if !(validateIpAddress(serverHost) ||
validateDomainName(serverHost) ||
validatePort(serverPort)){
return false
}
if password.isEmpty {
return false
}
return true
}
}

View File

@ -0,0 +1,359 @@
//
// PreferencesWindowController.swift
// ShadowsocksX-NG
//
// Created by on 16/6/6.
// Copyright © 2016 qiuyuzhou. All rights reserved.
//
import Cocoa
import RxCocoa
import RxSwift
class PreferencesWindowController: NSWindowController
, NSTableViewDataSource, NSTableViewDelegate {
@IBOutlet weak var profilesTableView: NSTableView!
@IBOutlet weak var profileBox: NSBox!
@IBOutlet weak var hostTextField: NSTextField!
@IBOutlet weak var portTextField: NSTextField!
@IBOutlet weak var methodTextField: NSComboBox!
@IBOutlet weak var passwordTabView: NSTabView!
@IBOutlet weak var passwordTextField: NSTextField!
@IBOutlet weak var passwordSecureTextField: NSSecureTextField!
@IBOutlet weak var togglePasswordVisibleButton: NSButton!
@IBOutlet weak var remarkTextField: NSTextField!
@IBOutlet weak var removeButton: NSButton!
let tableViewDragType: String = "ss.server.profile.data"
var serverConfigs = [ProxyServerModel]()
var editingConfig:ProxyServerModel?
var enabledKcptunSubDisosable: Disposable?
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
if serverConfigs.count == 0 {
serverConfigs.append(ProxyServerModel())
}
methodTextField.addItems(withObjectValues: [
"aes-128-gcm",
"aes-192-gcm",
"aes-256-gcm",
"aes-128-cfb",
"aes-192-cfb",
"aes-256-cfb",
"aes-128-ctr",
"aes-192-ctr",
"aes-256-ctr",
"camellia-128-cfb",
"camellia-192-cfb",
"camellia-256-cfb",
"bf-cfb",
"chacha20-ietf-poly1305",
"salsa20",
"chacha20",
"chacha20-ietf",
"rc4-md5",
])
profilesTableView.reloadData()
updateProfileBoxVisible()
}
override func awakeFromNib() {
profilesTableView.registerForDraggedTypes([NSPasteboard.PasteboardType(rawValue: tableViewDragType)])
profilesTableView.allowsMultipleSelection = true
}
@IBAction func addProfile(_ sender: NSButton) {
if !(editingConfig?.isValid() ?? true){
shakeWindows()
return
}
profilesTableView.beginUpdates()
let profile = ProxyServerModel()
profile.remark = "New Server"
serverConfigs.append(profile)
let index = IndexSet(integer: serverConfigs.count-1)
profilesTableView.insertRows(at: index, withAnimation: NSTableView.AnimationOptions.effectFade)
self.profilesTableView.scrollRowToVisible(self.serverConfigs.count-1)
self.profilesTableView.selectRowIndexes(index, byExtendingSelection: false)
profilesTableView.endUpdates()
updateProfileBoxVisible()
}
@IBAction func removeProfile(_ sender: NSButton) {
let index = Int(profilesTableView.selectedRowIndexes.first!)
var deleteCount = 0
if index >= 0 {
profilesTableView.beginUpdates()
for (_, toDeleteIndex) in profilesTableView.selectedRowIndexes.enumerated() {
print(serverConfigs.count)
serverConfigs.remove(at: toDeleteIndex - deleteCount)
profilesTableView.removeRows(at: IndexSet(integer: toDeleteIndex - deleteCount), withAnimation: NSTableView.AnimationOptions.effectFade)
deleteCount += 1
}
profilesTableView.endUpdates()
}
self.profilesTableView.scrollRowToVisible(index-1)
self.profilesTableView.selectRowIndexes(IndexSet(integer: index-1), byExtendingSelection: false)
updateProfileBoxVisible()
}
@IBAction func ok(_ sender: NSButton) {
if !(editingConfig?.isValid() ?? false) {
shakeWindows()
return
}
window?.performClose(nil)
}
@IBAction func cancel(_ sender: NSButton) {
window?.performClose(self)
}
@IBAction func duplicate(_ sender: Any) {
var copyCount = 0
for (_, toDuplicateIndex) in profilesTableView.selectedRowIndexes.enumerated() {
print(serverConfigs.count)
let profile = serverConfigs[toDuplicateIndex + copyCount]
let duplicateProfile = profile.copy() as! ProxyServerModel
serverConfigs.insert(duplicateProfile, at:toDuplicateIndex + copyCount)
profilesTableView.beginUpdates()
let index = IndexSet(integer: toDuplicateIndex + copyCount)
profilesTableView.insertRows(at: index, withAnimation: NSTableView.AnimationOptions.effectFade)
self.profilesTableView.scrollRowToVisible(toDuplicateIndex + copyCount)
self.profilesTableView.selectRowIndexes(index, byExtendingSelection: false)
profilesTableView.endUpdates()
copyCount += 1
}
updateProfileBoxVisible()
}
@IBAction func togglePasswordVisible(_ sender: Any) {
if passwordTabView.selectedTabViewItem?.identifier as! String == "secure" {
passwordTabView.selectTabViewItem(withIdentifier: "insecure")
togglePasswordVisibleButton.image = NSImage(named: NSImage.Name(rawValue: "icons8-Eye Filled-50"))
} else {
passwordTabView.selectTabViewItem(withIdentifier: "secure")
togglePasswordVisibleButton.image = NSImage(named: NSImage.Name(rawValue: "icons8-Blind Filled-50"))
}
}
func updateProfileBoxVisible() {
if serverConfigs.count <= 0 {
removeButton.isEnabled = false
}else{
removeButton.isEnabled = true
}
if serverConfigs.isEmpty {
profileBox.isHidden = true
} else {
profileBox.isHidden = false
}
}
func bindProfile(_ index:Int) {
NSLog("bind profile \(index)")
if let dis = enabledKcptunSubDisosable {
dis.dispose()
enabledKcptunSubDisosable = Optional.none
}
if index >= 0 && index < serverConfigs.count {
editingConfig = serverConfigs[index]
hostTextField.bind(NSBindingName(rawValue: "value"), to: editingConfig!, withKeyPath: "serverHost"
, options: [NSBindingOption.continuouslyUpdatesValue: true])
portTextField.bind(NSBindingName(rawValue: "value"), to: editingConfig!, withKeyPath: "serverPort"
, options: [NSBindingOption.continuouslyUpdatesValue: true])
methodTextField.bind(NSBindingName(rawValue: "value"), to: editingConfig!, withKeyPath: "method"
, options: [NSBindingOption.continuouslyUpdatesValue: true])
passwordTextField.bind(NSBindingName(rawValue: "value"), to: editingConfig!, withKeyPath: "password"
, options: [NSBindingOption.continuouslyUpdatesValue: true])
passwordSecureTextField.bind(NSBindingName(rawValue: "value"), to: editingConfig!, withKeyPath: "password"
, options: [NSBindingOption.continuouslyUpdatesValue: true])
remarkTextField.bind(NSBindingName(rawValue: "value"), to: editingConfig!, withKeyPath: "remark"
, options: [NSBindingOption.continuouslyUpdatesValue: true])
} else {
editingConfig = nil
hostTextField.unbind(NSBindingName(rawValue: "value"))
portTextField.unbind(NSBindingName(rawValue: "value"))
methodTextField.unbind(NSBindingName(rawValue: "value"))
passwordTextField.unbind(NSBindingName(rawValue: "value"))
remarkTextField.unbind(NSBindingName(rawValue: "value"))
}
}
func getDataAtRow(_ index:Int) -> (String) {
let profile = serverConfigs[index]
if !profile.remark.isEmpty {
return profile.remark
} else {
return profile.serverHost
}
}
//--------------------------------------------------
// For NSTableViewDataSource
func numberOfRows(in tableView: NSTableView) -> Int {
return serverConfigs.count
}
func tableView(_ tableView: NSTableView
, objectValueFor tableColumn: NSTableColumn?
, row: Int) -> Any? {
let title = getDataAtRow(row)
if tableColumn?.identifier == NSUserInterfaceItemIdentifier("main") {
return title
} else if tableColumn?.identifier == NSUserInterfaceItemIdentifier("status") {
return nil
}
return ""
}
// Drag & Drop reorder rows
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
let item = NSPasteboardItem()
item.setString(String(row), forType: NSPasteboard.PasteboardType(rawValue: tableViewDragType))
return item
}
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int
, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
if dropOperation == .above {
return .move
}
return NSDragOperation()
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo
, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
var oldIndexes = [Int]()
info.enumerateDraggingItems(options: [], for: tableView, classes: [NSPasteboardItem.self], searchOptions: [:], using: {
(draggingItem: NSDraggingItem, idx: Int, stop: UnsafeMutablePointer<ObjCBool>) in
if let str = (draggingItem.item as! NSPasteboardItem).string(forType: NSPasteboard.PasteboardType(rawValue: self.tableViewDragType)), let index = Int(str) {
oldIndexes.append(index)
}
})
var oldIndexOffset = 0
var newIndexOffset = 0
// For simplicity, the code below uses `tableView.moveRowAtIndex` to move rows around directly.
// You may want to move rows in your content array and then call `tableView.reloadData()` instead.
tableView.beginUpdates()
for oldIndex in oldIndexes {
if oldIndex < row {
let o = serverConfigs.remove(at: oldIndex + oldIndexOffset)
serverConfigs.insert(o, at:row - 1)
tableView.moveRow(at: oldIndex + oldIndexOffset, to: row - 1)
oldIndexOffset -= 1
} else {
let o = serverConfigs.remove(at: oldIndex)
serverConfigs.insert(o, at:row + newIndexOffset)
tableView.moveRow(at: oldIndex, to: row + newIndexOffset)
newIndexOffset += 1
}
}
tableView.endUpdates()
return true
}
//--------------------------------------------------
// For NSTableViewDelegate
func tableView(_ tableView: NSTableView
, shouldEdit tableColumn: NSTableColumn?, row: Int) -> Bool {
return false
}
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
if row < 0 {
editingConfig = nil
return true
}
if editingConfig != nil {
if !(editingConfig?.isValid() ?? false) {
return false
}
}
return true
}
func tableViewSelectionDidChange(_ notification: Notification) {
if profilesTableView.selectedRow >= 0 {
bindProfile(profilesTableView.selectedRow)
} else {
if !serverConfigs.isEmpty {
let index = IndexSet(integer: serverConfigs.count - 1)
profilesTableView.selectRowIndexes(index, byExtendingSelection: false)
}
}
}
func shakeWindows(){
let numberOfShakes:Int = 8
let durationOfShake:Float = 0.5
let vigourOfShake:Float = 0.05
let frame:CGRect = (window?.frame)!
let shakeAnimation = CAKeyframeAnimation()
let shakePath = CGMutablePath()
shakePath.move(to: CGPoint(x:NSMinX(frame), y:NSMinY(frame)))
for _ in 1...numberOfShakes{
shakePath.addLine(to: CGPoint(x: NSMinX(frame) - frame.size.width * CGFloat(vigourOfShake), y: NSMinY(frame)))
shakePath.addLine(to: CGPoint(x: NSMinX(frame) + frame.size.width * CGFloat(vigourOfShake), y: NSMinY(frame)))
}
shakePath.closeSubpath()
shakeAnimation.path = shakePath
shakeAnimation.duration = CFTimeInterval(durationOfShake)
window?.animations = [NSAnimatablePropertyKey(rawValue: "frameOrigin"):shakeAnimation]
window?.animator().setFrameOrigin(window!.frame.origin)
}
}

View File

@ -0,0 +1,395 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
<capability name="box content view" minToolsVersion="7.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="PreferencesWindowController" customModule="ClashX" customModuleProvider="target">
<connections>
<outlet property="hostTextField" destination="R4F-j7-GkK" id="a1I-WO-Qdj"/>
<outlet property="methodTextField" destination="ef4-8J-eFn" id="OXd-fC-ICR"/>
<outlet property="passwordSecureTextField" destination="ZXA-oi-Zv3" id="ZMF-s4-w53"/>
<outlet property="passwordTabView" destination="DHz-Hx-kZ5" id="8W3-H3-Ezq"/>
<outlet property="passwordTextField" destination="3Ad-X4-DBi" id="FHf-t3-D8t"/>
<outlet property="portTextField" destination="lng-AE-g0J" id="7b1-ox-WSL"/>
<outlet property="profileBox" destination="oZ5-85-pwY" id="D19-PQ-X7E"/>
<outlet property="profilesTableView" destination="r91-ho-Lum" id="TNk-f6-Vgo"/>
<outlet property="remarkTextField" destination="q3C-S0-iNn" id="DSv-lV-PX7"/>
<outlet property="removeButton" destination="3ei-2f-kHB" id="DdP-dA-coT"/>
<outlet property="togglePasswordVisibleButton" destination="jDI-cn-wYa" id="wc1-ra-kya"/>
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Server Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" oneShot="NO" animationBehavior="default" id="F0z-JX-Cv5">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<rect key="contentRect" x="423" y="365" width="613" height="332"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="613" height="332"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView focusRingType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="u4U-Ju-FJV">
<rect key="frame" x="20" y="80" width="233" height="232"/>
<clipView key="contentView" focusRingType="none" id="1oC-7s-16v">
<rect key="frame" x="1" y="1" width="231" height="230"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnSelection="YES" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" id="r91-ho-Lum">
<rect key="frame" x="0.0" y="0.0" width="231" height="230"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="status" width="20" minWidth="10" maxWidth="3.4028234663852886e+38" id="wR0-vc-Gtr">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<imageCell key="dataCell" refusesFirstResponder="YES" alignment="left" identifier="status" imageScaling="proportionallyDown" id="aBb-XB-tD7"/>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
</tableColumn>
<tableColumn identifier="main" width="135" minWidth="40" maxWidth="1000" id="6gc-9b-Qnw">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" identifier="main" title="Text" id="COZ-Qr-bmU">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="fz3-X6-PbB"/>
<outlet property="delegate" destination="-2" id="6zR-v1-wZj"/>
<outlet property="menu" destination="QmU-th-vjP" id="J0d-c9-pYs"/>
</connections>
</tableView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="jTp-ja-h3t">
<rect key="frame" x="1" y="206" width="163" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="dLS-Vz-L6A">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<box boxType="custom" borderType="none" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="oZ5-85-pwY">
<rect key="frame" x="273" y="61" width="320" height="251"/>
<view key="contentView" id="a3z-VL-3xV">
<rect key="frame" x="0.0" y="0.0" width="320" height="251"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HPg-NP-kjP">
<rect key="frame" x="46" y="212" width="58" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Address:" id="yHs-XE-XEB">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Otb-CO-KUH">
<rect key="frame" x="235" y="214" width="9" height="17"/>
<constraints>
<constraint firstAttribute="width" constant="5" id="JAU-I8-jVc"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title=":" id="Ibr-Gs-5Js">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<comboBox verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ef4-8J-eFn">
<rect key="frame" x="110" y="177" width="189" height="26"/>
<comboBoxCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" completes="NO" numberOfVisibleItems="11" id="5Qb-ey-uS5">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</comboBoxCell>
</comboBox>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kft-TG-O5S">
<rect key="frame" x="30" y="182" width="74" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Encryption:" id="mOh-nD-7EX">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="q3C-S0-iNn">
<rect key="frame" x="110" y="119" width="193" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="oxu-qq-MGC">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Baj-Yh-kmj">
<rect key="frame" x="43" y="122" width="61" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Remarks:" id="MiN-VE-FtC">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="R4F-j7-GkK">
<rect key="frame" x="110" y="209" width="119" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="IP" drawsBackground="YES" id="MWO-hQ-nMt">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lng-AE-g0J">
<rect key="frame" x="246" y="209" width="50" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="Ahb-NM-Zyb"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="Port" drawsBackground="YES" id="e1F-jd-e0J">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</textFieldCell>
</textField>
<tabView focusRingType="none" drawsBackground="NO" type="noTabsNoBorder" initialItem="aRD-sh-uEl" translatesAutoresizingMaskIntoConstraints="NO" id="DHz-Hx-kZ5">
<rect key="frame" x="110" y="151" width="158" height="22"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="Secure" identifier="secure" id="aRD-sh-uEl">
<view key="view" id="rXs-ye-nly">
<rect key="frame" x="0.0" y="0.0" width="158" height="22"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<secureTextField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZXA-oi-Zv3">
<rect key="frame" x="0.0" y="0.0" width="158" height="22"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="zuN-Jd-LeS">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</secureTextFieldCell>
</secureTextField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="ZXA-oi-Zv3" secondAttribute="trailing" id="N5U-Eb-r6N"/>
<constraint firstItem="ZXA-oi-Zv3" firstAttribute="leading" secondItem="rXs-ye-nly" secondAttribute="leading" id="kHp-7I-hYq"/>
<constraint firstItem="ZXA-oi-Zv3" firstAttribute="top" secondItem="rXs-ye-nly" secondAttribute="top" id="oRQ-oR-A5o"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="Insecure" identifier="insecure" id="SYv-Tn-tur">
<view key="view" id="Z6k-mP-BgX">
<rect key="frame" x="0.0" y="0.0" width="135" height="22"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3Ad-X4-DBi">
<rect key="frame" x="0.0" y="0.0" width="135" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="DNt-0X-3Z0">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="3Ad-X4-DBi" firstAttribute="top" secondItem="Z6k-mP-BgX" secondAttribute="top" id="GRU-7C-6XV"/>
<constraint firstAttribute="trailing" secondItem="3Ad-X4-DBi" secondAttribute="trailing" id="cRR-i4-0ty"/>
<constraint firstItem="3Ad-X4-DBi" firstAttribute="leading" secondItem="Z6k-mP-BgX" secondAttribute="leading" id="s6R-BF-mOG"/>
</constraints>
</view>
</tabViewItem>
</tabViewItems>
</tabView>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="jDI-cn-wYa">
<rect key="frame" x="277" y="149" width="26" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="26" id="vGB-iL-nWP"/>
</constraints>
<buttonCell key="cell" type="squareTextured" bezelStyle="texturedSquare" image="icons8-Blind Filled-50" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="axesIndependently" inset="2" id="8Bw-DM-zYg">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="togglePasswordVisible:" target="-2" id="3kh-Pz-mr0"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Qfe-Ql-iCO">
<rect key="frame" x="38" y="153" width="66" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Password:" id="kil-xC-HPD">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="Baj-Yh-kmj" firstAttribute="baseline" secondItem="q3C-S0-iNn" secondAttribute="baseline" id="0Fs-Yi-WBo"/>
<constraint firstItem="lng-AE-g0J" firstAttribute="leading" secondItem="Otb-CO-KUH" secondAttribute="trailing" constant="4" id="0bx-FE-Nqz"/>
<constraint firstItem="R4F-j7-GkK" firstAttribute="baseline" secondItem="lng-AE-g0J" secondAttribute="baseline" id="0dG-a6-exG"/>
<constraint firstItem="DHz-Hx-kZ5" firstAttribute="leading" secondItem="Qfe-Ql-iCO" secondAttribute="trailing" constant="8" symbolic="YES" id="1bR-S3-Tdq"/>
<constraint firstItem="ef4-8J-eFn" firstAttribute="top" secondItem="R4F-j7-GkK" secondAttribute="bottom" constant="8" symbolic="YES" id="41P-Ix-it2"/>
<constraint firstAttribute="trailing" secondItem="lng-AE-g0J" secondAttribute="trailing" constant="24" id="6W3-BA-gYo"/>
<constraint firstItem="R4F-j7-GkK" firstAttribute="top" secondItem="a3z-VL-3xV" secondAttribute="top" constant="20" symbolic="YES" id="Dkz-UA-ymg"/>
<constraint firstItem="DHz-Hx-kZ5" firstAttribute="top" secondItem="ef4-8J-eFn" secondAttribute="bottom" constant="8" symbolic="YES" id="I7k-9o-SLi"/>
<constraint firstItem="jDI-cn-wYa" firstAttribute="leading" secondItem="DHz-Hx-kZ5" secondAttribute="trailing" constant="9" id="IMV-t5-Set"/>
<constraint firstItem="jDI-cn-wYa" firstAttribute="trailing" secondItem="q3C-S0-iNn" secondAttribute="trailing" id="Idl-zd-MSU"/>
<constraint firstItem="DHz-Hx-kZ5" firstAttribute="leading" secondItem="q3C-S0-iNn" secondAttribute="leading" id="JBi-Dy-gPS"/>
<constraint firstAttribute="trailing" secondItem="jDI-cn-wYa" secondAttribute="trailing" constant="17" id="JSl-uN-iMh"/>
<constraint firstItem="ef4-8J-eFn" firstAttribute="leading" secondItem="DHz-Hx-kZ5" secondAttribute="leading" id="L85-np-Xpn"/>
<constraint firstItem="q3C-S0-iNn" firstAttribute="leading" secondItem="Baj-Yh-kmj" secondAttribute="trailing" constant="8" symbolic="YES" id="LTy-e7-h27"/>
<constraint firstItem="DHz-Hx-kZ5" firstAttribute="bottom" secondItem="jDI-cn-wYa" secondAttribute="bottom" id="RM1-vq-zAm"/>
<constraint firstItem="Kft-TG-O5S" firstAttribute="centerY" secondItem="ef4-8J-eFn" secondAttribute="centerY" id="RYD-o2-vjB"/>
<constraint firstItem="Kft-TG-O5S" firstAttribute="leading" secondItem="a3z-VL-3xV" secondAttribute="leading" constant="32" id="TsS-51-KLG"/>
<constraint firstItem="ef4-8J-eFn" firstAttribute="leading" secondItem="Kft-TG-O5S" secondAttribute="trailing" constant="8" symbolic="YES" id="VGj-2V-kmi"/>
<constraint firstItem="Otb-CO-KUH" firstAttribute="leading" secondItem="R4F-j7-GkK" secondAttribute="trailing" constant="8" symbolic="YES" id="dL8-po-Zhh"/>
<constraint firstItem="HPg-NP-kjP" firstAttribute="baseline" secondItem="R4F-j7-GkK" secondAttribute="baseline" id="fb7-sB-eHL"/>
<constraint firstItem="DHz-Hx-kZ5" firstAttribute="top" secondItem="jDI-cn-wYa" secondAttribute="top" id="fbb-RF-Wvf"/>
<constraint firstItem="Qfe-Ql-iCO" firstAttribute="leading" secondItem="a3z-VL-3xV" secondAttribute="leading" constant="40" id="fw1-Zg-LaZ"/>
<constraint firstItem="lng-AE-g0J" firstAttribute="trailing" secondItem="ef4-8J-eFn" secondAttribute="trailing" id="gxe-uL-y5w"/>
<constraint firstItem="R4F-j7-GkK" firstAttribute="leading" secondItem="HPg-NP-kjP" secondAttribute="trailing" constant="8" symbolic="YES" id="hKJ-ZW-uLY"/>
<constraint firstItem="Otb-CO-KUH" firstAttribute="top" secondItem="lng-AE-g0J" secondAttribute="top" id="kLj-6Z-ZDw"/>
<constraint firstItem="R4F-j7-GkK" firstAttribute="leading" secondItem="ef4-8J-eFn" secondAttribute="leading" id="opP-Lo-SO0"/>
<constraint firstItem="Qfe-Ql-iCO" firstAttribute="centerY" secondItem="DHz-Hx-kZ5" secondAttribute="centerY" id="wKU-B5-A3m"/>
<constraint firstItem="q3C-S0-iNn" firstAttribute="top" secondItem="DHz-Hx-kZ5" secondAttribute="bottom" constant="10" id="xus-im-ZK7"/>
</constraints>
</view>
<color key="fillColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</box>
<box boxType="custom" borderType="none" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="Gqv-5O-Wwf">
<rect key="frame" x="20" y="61" width="233" height="19"/>
<view key="contentView" id="MbP-FS-YEs">
<rect key="frame" x="0.0" y="0.0" width="233" height="19"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="4ig-lF-m2R">
<rect key="frame" x="0.0" y="-1" width="22" height="21"/>
<constraints>
<constraint firstAttribute="width" constant="22" id="sgm-c9-nQI"/>
</constraints>
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="VkE-bG-mJb">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="addProfile:" target="-2" id="NEh-IP-KO8"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3ei-2f-kHB">
<rect key="frame" x="20" y="-1" width="22" height="21"/>
<constraints>
<constraint firstAttribute="width" constant="22" id="LYH-ae-nU6"/>
</constraints>
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Nu6-Aw-ihE">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="removeProfile:" target="-2" id="CJC-GL-qeS"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="4ig-lF-m2R" firstAttribute="leading" secondItem="MbP-FS-YEs" secondAttribute="leading" id="25E-Gc-eBh"/>
<constraint firstItem="4ig-lF-m2R" firstAttribute="top" secondItem="MbP-FS-YEs" secondAttribute="top" id="3Ss-BU-JcV"/>
<constraint firstItem="4ig-lF-m2R" firstAttribute="baseline" secondItem="3ei-2f-kHB" secondAttribute="baseline" id="Pp6-ir-tQB"/>
<constraint firstAttribute="bottom" secondItem="4ig-lF-m2R" secondAttribute="bottom" id="dIB-U3-h90"/>
<constraint firstItem="3ei-2f-kHB" firstAttribute="leading" secondItem="MbP-FS-YEs" secondAttribute="leading" constant="20" symbolic="YES" id="fOJ-7v-G14"/>
</constraints>
</view>
<color key="fillColor" red="1" green="1" blue="1" alpha="0.59999999999999998" colorSpace="calibratedRGB"/>
</box>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="yyD-qq-aSk">
<rect key="frame" x="518" y="13" width="81" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="SDg-E4-Aza"/>
</constraints>
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="zPE-oD-PwK">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="ok:" target="-2" id="ifI-e4-Htf"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kGm-Zm-ipY">
<rect key="frame" x="437" y="13" width="81" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="69" id="P30-kh-sbD"/>
</constraints>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="j03-9E-uHW">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="cancel:" target="-2" id="514-4D-a6S"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="oZ5-85-pwY" secondAttribute="trailing" constant="20" symbolic="YES" id="6XB-Xo-ULh"/>
<constraint firstItem="oZ5-85-pwY" firstAttribute="trailing" secondItem="yyD-qq-aSk" secondAttribute="trailing" id="CEw-Ad-ctb"/>
<constraint firstItem="u4U-Ju-FJV" firstAttribute="top" secondItem="oZ5-85-pwY" secondAttribute="top" id="IMn-dq-QUj"/>
<constraint firstItem="Gqv-5O-Wwf" firstAttribute="top" secondItem="u4U-Ju-FJV" secondAttribute="bottom" id="IYg-B8-HlS"/>
<constraint firstItem="yyD-qq-aSk" firstAttribute="leading" secondItem="kGm-Zm-ipY" secondAttribute="trailing" constant="12" symbolic="YES" id="JBX-pg-6SB"/>
<constraint firstAttribute="bottom" secondItem="kGm-Zm-ipY" secondAttribute="bottom" constant="20" symbolic="YES" id="LQl-3C-29i"/>
<constraint firstItem="oZ5-85-pwY" firstAttribute="leading" secondItem="Gqv-5O-Wwf" secondAttribute="trailing" constant="20" symbolic="YES" id="bvQ-7l-IZO"/>
<constraint firstItem="u4U-Ju-FJV" firstAttribute="leading" secondItem="Gqv-5O-Wwf" secondAttribute="leading" id="jtv-6s-2wd"/>
<constraint firstItem="oZ5-85-pwY" firstAttribute="leading" secondItem="u4U-Ju-FJV" secondAttribute="trailing" constant="20" symbolic="YES" id="nkb-ca-YNA"/>
<constraint firstItem="kGm-Zm-ipY" firstAttribute="top" secondItem="oZ5-85-pwY" secondAttribute="bottom" constant="20" symbolic="YES" id="rEF-Az-fO2"/>
<constraint firstItem="Gqv-5O-Wwf" firstAttribute="bottom" secondItem="oZ5-85-pwY" secondAttribute="bottom" id="sb3-Xg-ZeX"/>
<constraint firstItem="kGm-Zm-ipY" firstAttribute="baseline" secondItem="yyD-qq-aSk" secondAttribute="baseline" id="tvk-rK-yV5"/>
<constraint firstItem="u4U-Ju-FJV" firstAttribute="top" secondItem="se5-gp-TjO" secondAttribute="top" constant="20" symbolic="YES" id="vkk-Ys-and"/>
<constraint firstItem="u4U-Ju-FJV" firstAttribute="leading" secondItem="se5-gp-TjO" secondAttribute="leading" constant="20" symbolic="YES" id="yg3-ls-7P7"/>
<constraint firstItem="oZ5-85-pwY" firstAttribute="leading" secondItem="se5-gp-TjO" secondAttribute="leading" constant="273" id="zO0-Le-Yu1"/>
</constraints>
</view>
<connections>
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
</connections>
<point key="canvasLocation" x="417.5" y="61"/>
</window>
<numberFormatter formatterBehavior="default10_4" usesGroupingSeparator="NO" groupingSize="0" minimumIntegerDigits="0" maximumIntegerDigits="42" id="QZc-kt-D7Z" userLabel="Port Number Formatter">
<real key="minimum" value="1"/>
<real key="maximum" value="65535"/>
</numberFormatter>
<menu showsStateColumn="NO" id="QmU-th-vjP">
<items>
<menuItem title="Clone" id="bl9-lq-u9V">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="duplicate:" target="-2" id="dEb-Dt-yBW"/>
</connections>
</menuItem>
</items>
<point key="canvasLocation" x="-25.5" y="171.5"/>
</menu>
<userDefaultsController representsSharedInstance="YES" id="UV9-ar-oJ3"/>
</objects>
<resources>
<image name="NSAddTemplate" width="11" height="11"/>
<image name="NSRemoveTemplate" width="11" height="11"/>
<image name="icons8-Blind Filled-50" width="50" height="50"/>
</resources>
</document>