Showing preview only (400K chars total). Download the full file or copy to clipboard to get everything.
Repository: cbreak-black/ZetaWatch
Branch: master
Commit: 73baba945cab
Files: 70
Total size: 377.9 KB
Directory structure:
gitextract_u2m5ltbd/
├── .gitignore
├── .gitmodules
├── CommonAuthorization/
│ ├── CommonAuthorization.h
│ ├── CommonAuthorization.m
│ └── CommonAuthorization.strings
├── LICENSE.md
├── README.md
├── ZetaAuthorizationHelper/
│ ├── Info.plist
│ ├── Launchd.plist
│ ├── ZetaAuthorizationHelper.h
│ ├── ZetaAuthorizationHelper.mm
│ ├── ZetaAuthorizationHelperProtocol.h
│ ├── ZetaCPPUtils.hpp
│ └── main.m
├── ZetaLoginItemHelper/
│ ├── Info.plist
│ └── main.m
├── ZetaWatch/
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ └── Zeta.imageset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ ├── Localizable.strings
│ │ ├── MainMenu.xib
│ │ ├── NewFS.xib
│ │ └── NewVol.xib
│ ├── Info.plist
│ ├── InvariantDisks/
│ │ ├── IDDiskArbitrationDispatcher.cpp
│ │ ├── IDDiskArbitrationDispatcher.hpp
│ │ ├── IDDiskArbitrationHandler.hpp
│ │ ├── IDDiskArbitrationUtils.cpp
│ │ └── IDDiskArbitrationUtils.hpp
│ ├── PathValueTransformer.m
│ ├── SizeTransformer.mm
│ ├── ZetaAuthorization.h
│ ├── ZetaAuthorization.mm
│ ├── ZetaAutoImporter.h
│ ├── ZetaAutoImporter.mm
│ ├── ZetaBookmarkMenu.h
│ ├── ZetaBookmarkMenu.mm
│ ├── ZetaCommanderBase.h
│ ├── ZetaCommanderBase.mm
│ ├── ZetaConfirmDialog.h
│ ├── ZetaConfirmDialog.mm
│ ├── ZetaDictQueryDialog.h
│ ├── ZetaDictQueryDialog.mm
│ ├── ZetaFileSystemPropertyMenu.h
│ ├── ZetaFileSystemPropertyMenu.mm
│ ├── ZetaFormatHelpers.cpp
│ ├── ZetaFormatHelpers.hpp
│ ├── ZetaImportMenu.h
│ ├── ZetaImportMenu.mm
│ ├── ZetaKeyLoader.h
│ ├── ZetaKeyLoader.mm
│ ├── ZetaMainMenu.h
│ ├── ZetaMainMenu.mm
│ ├── ZetaNotificationCenter.h
│ ├── ZetaNotificationCenter.mm
│ ├── ZetaPoolPropertyMenu.h
│ ├── ZetaPoolPropertyMenu.mm
│ ├── ZetaPoolWatcher.h
│ ├── ZetaPoolWatcher.mm
│ ├── ZetaQueryDialog.h
│ ├── ZetaQueryDialog.mm
│ ├── ZetaSnapshotMenu.h
│ ├── ZetaSnapshotMenu.mm
│ ├── ZetaWatch.entitlements
│ ├── ZetaWatchDelegate.h
│ ├── ZetaWatchDelegate.mm
│ └── main.m
├── ZetaWatch.xcodeproj/
│ ├── project.pbxproj
│ └── project.xcworkspace/
│ └── contents.xcworkspacedata
└── uninstall-helper.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
Archive
DerivedData
xcuserdata
================================================
FILE: .gitmodules
================================================
[submodule "ThirdParty/Sparkle"]
path = ThirdParty/Sparkle
url = ../Sparkle.git
[submodule "ZFSWrapper"]
path = ZFSWrapper
url = ../ZFSWrapper
================================================
FILE: CommonAuthorization/CommonAuthorization.h
================================================
//
// CommonAuthorization.h
// ZetaWatch
//
// Created by cbreak on 18.01.01.
// Copyright © 2018 the-color-black.net. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface CommonAuthorization : NSObject
//! For a given command selector, return the associated authorization right name.
+ (NSString *)authorizationRightForCommand:(SEL)command;
//! Set up the default authorization rights in the authorization database.
+ (void)setupAuthorizationRights:(AuthorizationRef)authRef;
@end
================================================
FILE: CommonAuthorization/CommonAuthorization.m
================================================
//
// CommonAuthorization.m
// ZetaWatch
//
// Created by cbreak on 18.01.01.
// Copyright © 2018 the-color-black.net. All rights reserved.
//
#import "CommonAuthorization.h"
#import "ZetaAuthorizationHelperProtocol.h"
@implementation CommonAuthorization
static NSString * kKeyAuthRightName = @"authRightName";
static NSString * kKeyAuthRightDefault = @"authRightDefault";
static NSString * kKeyAuthRightDesc = @"authRightDescription";
/*!
+commandInfo returns a dictionary that represents everything we need to know about the
authorized commands supported by the app. Each dictionary key is the string form of
the command selector. The corresponding object is a dictionary that contains three items:
o kKeyAuthRightName is the name of the authorization right itself. This is used by
both the app (when creating rights and when pre-authorizing rights) and by the tool
(when doing the final authorization check).
o kKeyAuthRightDefault is the default right specification, used by the app to when
it needs to create the default right specification. This is commonly a string contacting
a rule a name, but it can potentially be more complex. See the discussion of the
rightDefinition parameter of AuthorizationRightSet.
o kKeyAuthRightDesc is a user-visible description of the right. This is used by the
app when it needs to create the default right specification. Actually, string is used
to look up a localized version of the string in "CommonAuthorization.strings".
This file is generated by the "genstrings" cli application.
*/
+ (NSDictionary *)commandInfo
{
static dispatch_once_t sOnceToken;
static NSDictionary * sCommandInfo;
dispatch_once(&sOnceToken,^{
NSDictionary * dictStop =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.stop",
kKeyAuthRightDefault: @kAuthorizationRuleClassAllow,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying stop its helper.",
@"prompt shown when user is required to authorize helper termination"
)
};
NSDictionary * dictImport =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.import",
kKeyAuthRightDefault: @kAuthorizationRuleClassAllow,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to import a pool.",
@"prompt shown when user is required to authorize a zpool import"
)
};
NSDictionary * dictExport =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.export",
kKeyAuthRightDefault: @kAuthorizationRuleClassAllow,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to export a pool.",
@"prompt shown when user is required to authorize a zpool export"
)
};
NSDictionary * dictMount =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.mount",
kKeyAuthRightDefault: @kAuthorizationRuleClassAllow,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to mount a filesystem.",
@"prompt shown when user is required to authorize a zfs mount"
)
};
NSDictionary * dictUnmount =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.unmount",
kKeyAuthRightDefault: @kAuthorizationRuleClassAllow,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to unmount a filesystem.",
@"prompt shown when user is required to authorize a zfs unmount"
)
};
NSDictionary * dictSnapshot =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.snapshot",
kKeyAuthRightDefault: @kAuthorizationRuleClassAllow,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to snapshot a filesystem.",
@"prompt shown when user is required to authorize a zfs snapshot"
)
};
NSDictionary * dictRollback =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.rollback",
kKeyAuthRightDefault: @kAuthorizationRuleAuthenticateAsAdmin,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to roll back a filesystem.",
@"prompt shown when user is required to authorize a zfs rollback"
)
};
NSDictionary * dictClone =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.clone",
kKeyAuthRightDefault: @kAuthorizationRuleAuthenticateAsAdmin,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to clone a snapshot.",
@"prompt shown when user is required to authorize a zfs clone"
)
};
NSDictionary * dictCreate =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.create",
kKeyAuthRightDefault: @kAuthorizationRuleAuthenticateAsAdmin,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to create a filesystem.",
@"prompt shown when user is required to authorize a zfs create"
)
};
NSDictionary * dictDestroy =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.destroy",
kKeyAuthRightDefault: @kAuthorizationRuleAuthenticateAsAdmin,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to destroy a filesystem.",
@"prompt shown when user is required to authorize a zfs destroy"
)
};
NSDictionary * dictKey =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.key",
kKeyAuthRightDefault: @kAuthorizationRuleClassAllow,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to operate on an encryption key.",
@"prompt shown when user is required to authorize a crypto key operation"
)
};
NSDictionary * dictScrub =
@{
kKeyAuthRightName: @"net.the-color-black.ZetaWatch.scrub",
kKeyAuthRightDefault: @kAuthorizationRuleClassAllow,
kKeyAuthRightDesc: NSLocalizedString(
@"ZetaWatch is trying to scrub a pool.",
@"prompt shown when user is required to authorize a zpool scrub"
)
};
sCommandInfo =
@{
NSStringFromSelector(@selector(stopHelperWithAuthorization:withReply:)): dictStop,
NSStringFromSelector(@selector(importPools:authorization:withReply:)): dictImport,
NSStringFromSelector(@selector(importablePools:authorization:withReply:)): dictImport,
NSStringFromSelector(@selector(exportPools:authorization:withReply:)): dictExport,
NSStringFromSelector(@selector(mountFilesystems:authorization:withReply:)): dictMount,
NSStringFromSelector(@selector(unmountFilesystems:authorization:withReply:)): dictUnmount,
NSStringFromSelector(@selector(snapshotFilesystem:authorization:withReply:)):
dictSnapshot,
NSStringFromSelector(@selector(rollbackFilesystem:authorization:withReply:)):
dictRollback,
NSStringFromSelector(@selector(cloneSnapshot:authorization:withReply:)):
dictClone,
NSStringFromSelector(@selector(createFilesystem:authorization:withReply:)):
dictCreate,
NSStringFromSelector(@selector(createVolume:authorization:withReply:)):
dictCreate,
NSStringFromSelector(@selector(destroy:authorization:withReply:)):
dictDestroy,
NSStringFromSelector(@selector(loadKeyForFilesystem:authorization:withReply:)): dictKey,
NSStringFromSelector(@selector(unloadKeyForFilesystem:authorization:withReply:)): dictKey,
NSStringFromSelector(@selector(scrubPool:authorization:withReply:)): dictScrub,
};
});
return sCommandInfo;
}
+ (NSString *)authorizationRightForCommand:(SEL)command
{
return [self commandInfo][NSStringFromSelector(command)][kKeyAuthRightName];
}
+ (void)enumerateRightsUsingBlock:(void (^)(NSString * authRightName, id authRightDefault, NSString * authRightDesc))block
{
[self.commandInfo enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL * stop)
{
NSDictionary * commandDict = (NSDictionary *) obj;
assert([commandDict isKindOfClass:[NSDictionary class]]);
NSString * authRightName = [commandDict objectForKey:kKeyAuthRightName];
assert([authRightName isKindOfClass:[NSString class]]);
id authRightDefault = [commandDict objectForKey:kKeyAuthRightDefault];
assert(authRightDefault != nil);
NSString * authRightDesc = [commandDict objectForKey:kKeyAuthRightDesc];
assert([authRightDesc isKindOfClass:[NSString class]]);
block(authRightName, authRightDefault, authRightDesc);
}];
}
+ (void)setupAuthorizationRights:(AuthorizationRef)authRef
// See comment in header.
{
assert(authRef != NULL);
[CommonAuthorization enumerateRightsUsingBlock:^(NSString * authRightName, id authRightDefault, NSString * authRightDesc)
{
// First get the right. If we get back errAuthorizationDenied that means there's
// no current definition, so we add our default one.
OSStatus blockErr = AuthorizationRightGet([authRightName UTF8String], NULL);
if (blockErr == errAuthorizationDenied)
{
blockErr = AuthorizationRightSet(authRef, [authRightName UTF8String],
(__bridge CFTypeRef)authRightDefault,
(__bridge CFStringRef)authRightDesc,
NULL, CFSTR("CommonAuthorization")
);
assert(blockErr == errAuthorizationSuccess);
}
}];
}
@end
================================================
FILE: LICENSE.md
================================================
Copyright (c) 2014, Gerhard Röthlin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the Project nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
ZetaWatch
=========
![ZetaWatch displaying pool status and filesystems][ZFSImage]
ZetaWatch is a small OS X program that displays the zfs status in the menu bar, similar to
what iStat Menus does for other information. It is fairly well tested, but due to the
current state of libzfs and libzfs_core, changes will be required until the API
stabilizes. ZetaWatch is usually compiled for the latest available [ZFS release for Mac
OS](https://openzfsonosx.org/), and might not be compatible with other releases.
Currently supported features are:
* Show pool, vdev, filesystem stats
* Show pool / filesystem properties
* Start, stop, pause scrubs, and monitor their progress.
* Import and Export pools manually, or auto-import when they become available
* Mount / unmount datasets manually or at pool import automatically
* Load/Unload encryption keys for encrypted datasets manually or automatically
* Optionally store pass phrases in the Mac OS X Keychain
* Create, Display, Delete, Clone Snapshots or roll back to them
* Report errors in notification center when they are discovered
Installation
------------
ZetaWatch Releases can be downloaded from the [GitHub Releases Page](https://github.com/cbreak-black/ZetaWatch/releases).
Please verify that the Version of ZetaWatch matches your ZFS Version. Usually,
only the newest official Release is supported, since code changes are sometimes
required to be fully compatible with the new library version.
ZetaWatch does not require manual installation. Simply copy it into /Application or where
ever else it fits. The bundled helper tool gets installed automatically the first time the
program is started. This requires user-authentication.
ZetaWatch supports auto updates, if enabled.
For Developers
==============
ZFS Interaction
---------------
ZetaWatch communicates with zfs using `libzfs.dylib`, `libzfs_core.dylib` ,
`libzpool.dylib` and `libnvpair.dylib`, just like the command line tools do. This gives
it all the flexibility of the command line tools, at the cost of having to reimplement
functionality that is found in the tools and not the library. And since the libraries are
explicitly not meant to provide a stable ABI, ZetaWatch is also closely coupled to the
ZFS version it is built and written for.
All the ZFS interaction is wrapped in the ZFSWrapper library. This C++ library isolates
the issues mentioned above and provides a more convenient and safe API than the original
C interface does. The library is used both by the helper tool and the frontend app. This
is the most reusable part of ZetaWatch, and might be split out as separate project later.
* *ZFSUtils* contains most of the advanced functionality, such as C++ Wrappers around the
library, pool, vdev or file system handles. Those classes also have functionality to query
state and iterate over members.
* *ZFSNVList* provides a wrapper around the `nvpair_t` / `nvlist_t` data structure that
is used in ZFS for a lot of userland / kernel communication. It manages resources in both
owning and non-owning fashion, and allows for easier iteration over sequences.
* *ZFSStrings* translate ZFS status enums into the user facing emoji or string
description, optionally with localization. (Localization is not well tested or supported
at the moment.)
Helper Tool
-----------
The implementation of the helper tool follows apple's [EvenBetterAuthorizationSample].
The helper tool communicates with the user application via `AuthorizationService` and
`NSXPCConnection`. The application side of code for this is in `ZetaAuthorization.m`. The
RPC protocol can be found in `ZetaAuthorizationHelperProtocol.h`, and is implemented in
`ZetaAuthorizationHelper.mm`. The `CommonAuthorization.m` file contains the supported
commands and associated default permissions.
The helper tool can be uninstalled with the `uninstall-helper.sh` script. This is useful
for debugging the installation of the helper, or updating the helper without increasing
the bundle version.
Authorization
-------------
The ZetaWatch helper tool uses the Security framework to authorize users before performing
privileged operations. It currently supports the following permissions.
* `net.the-color-black.ZetaWatch.import`, allowed by default, required for importing a pool.
* `net.the-color-black.ZetaWatch.export`, allowed by default, required for exporting a pool.
* `net.the-color-black.ZetaWatch.mount`, allowed by default, required for mounting a dataset.
* `net.the-color-black.ZetaWatch.unmount`, allowed by default, required for unmounting a
dataset.
* `net.the-color-black.ZetaWatch.snapshot`, allowed by default, required for creating a
snapshot.
* `net.the-color-black.ZetaWatch.rollback`, requires admin authentication by default,
required for rolling back a filesystem.
* `net.the-color-black.ZetaWatch.clone`, requires admin authentication by default,
required for cloning a filesystem.
* `net.the-color-black.ZetaWatch.create`, requires admin authentication by default,
required for creating a new filesystem.
* `net.the-color-black.ZetaWatch.destroy`, requires admin authentication by default,
required for destroying a filesystem or snapshot.
* `net.the-color-black.ZetaWatch.key`, allowed by default, required for loading or
unloading a key for a dataset. This also includes the ability to auto mount / unmount them.
* `net.the-color-black.ZetaWatch.scrub`, allowed by default, required for starting,
stopping or pausing scrubs.
These permissions can be manipulated via the `security` command line program. To inspect
the current dataset creation permissions, and switching it to allow this to all users:
```
security authorizationdb read net.the-color-black.ZetaWatch.create
security authorizationdb write net.the-color-black.ZetaWatch.create allow
```
Permissions include `allow`, `deny` or `authenticate-admin`.
More detailed information about this topic can be found in the article apples documentation
about [AuthorizationServices] and [Managing the Authorization Database in OS X Mavericks].
Security & Code Signing
-----------------------
Official release builds are signed and notarized, and should run without issues even on
newer Mac OS X. But there are still issues with authentication reported with the program
not being recognized as signed. To verify security manually, the following commands can
be used:
```bash
codesign -v -v -d ZetaWatch.app
xcrun stapler validate -v ZetaWatch.app
```
Building ZetaWatch requires an apple developer account with DeveloperID signing
capabilities, since it uses [`SMJobBless`] to run a helper service as root. This service
executes actions on behalf of the user, such as mounting, unmounting or loading a key.
[Notarization] is required to create binaries that can be run without without warning on
the newest Mac OS X.
Self Updating
-------------
The self-updating uses [SparkleFramework]. Since the newest released sparkle does not yet
support hardened runtime, it needs to be compiled manually. Building the "Distribution"
target in the Sparkle submodule in release mode is sufficient.
The sparkle submodule contains a version that is slimmed down by removing most languages,
which saves space. Since ZetaWatch is not localized, this is not a problem.
To create a working fork, adjust the public key and update url in the Info.plist file.
ZFS Binary Compatibility
------------------------
Since ZetaWatch directly links to the zfs libraries, it only works if those are
compatible. And while Sparkle has built-in support for OS compatibility checking, it
doesn't have the same for other dependencies. There is support for custom appcast
filtering, to select a suitable version, but since the ZFS version and the ZetaWatch
version are kind of orthogonal, this didn't seem fitting.
The chosen solution was to have a ZFS version specific appcast URL, and make ZetaWatch
query the appropriate appcast. This allows updating ZetaWatch when the used ZFS version
changes, but also have several supported parallel builds. Currently, the only supported
ZFS version is 1.9.
License
=======
This program is copyrighted by me, because I wrote it.
This program is licensed under the "3-clause BSD" License. See the LICENSE.md file for
details.
[EvenBetterAuthorizationSample]: https://developer.apple.com/library/content/samplecode/EvenBetterAuthorizationSample/Introduction/Intro.html
[`SMJobBless`]: https://developer.apple.com/documentation/servicemanagement/1431078-smjobbless?language=objc
[Notarization]: https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution?language=objc
[ZFSImage]: https://raw.githubusercontent.com/cbreak-black/ZetaWatch/master/doc/ZetaWatch.jpg
[SparkleFramework]: https://sparkle-project.org/
[SparkleGithub]: https://github.com/sparkle-project/Sparkle
[AuthorizationServices]: https://developer.apple.com/documentation/security/authorization_services?language=objc
[Managing the Authorization Database in OS X Mavericks]: https://derflounder.wordpress.com/2014/02/16/managing-the-authorization-database-in-os-x-mavericks/
================================================
FILE: ZetaAuthorizationHelper/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleIdentifier</key>
<string>net.the-color-black.ZetaAuthorizationHelper</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>ZetaAuthorizationHelper</string>
<key>CFBundleVersion</key>
<string>$(ZETA_VERSION)</string>
<key>SMAuthorizedClients</key>
<array>
<string>anchor apple generic and identifier "net.the-color-black.ZetaWatch" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = "8THUW5GT6P")</string>
</array>
</dict>
</plist>
================================================
FILE: ZetaAuthorizationHelper/Launchd.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>net.the-color-black.ZetaAuthorizationHelper</string>
<key>MachServices</key>
<dict>
<key>net.the-color-black.ZetaAuthorizationHelper</key>
<true/>
</dict>
</dict>
</plist>
================================================
FILE: ZetaAuthorizationHelper/ZetaAuthorizationHelper.h
================================================
//
// ZetaAuthorizationHelper.h
// ZetaAuthorizationHelper
//
// Created by cbreak on 18.01.01.
// Copyright © 2018 the-color-black.net. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZetaAuthorizationHelper : NSObject
- (id)init;
- (void)run;
@end
================================================
FILE: ZetaAuthorizationHelper/ZetaAuthorizationHelper.mm
================================================
//
// ZetaAuthorizationHelper.m
// ZetaAuthorizationHelper
//
// Created by cbreak on 18.01.01.
// Copyright © 2018 the-color-black.net. All rights reserved.
//
#import "ZetaAuthorizationHelper.h"
#import "ZetaAuthorizationHelperProtocol.h"
#import "CommonAuthorization.h"
#include "ZFSWrapper/ZFSUtils.hpp"
#include "ZetaCPPUtils.hpp"
@interface ZetaAuthorizationHelper () <NSXPCListenerDelegate, ZetaAuthorizationHelperProtocol>
{
bool shouldRun;
}
@property (atomic, strong, readwrite) NSXPCListener * listener;
@end
NSMutableArray<NSString*> * toArray(std::vector<std::string> const & strings)
{
NSMutableArray<NSString*> * array = [[NSMutableArray<NSString*> alloc] initWithCapacity:strings.size()];
for (auto const & s : strings)
{
[array addObject:[NSString stringWithUTF8String:s.c_str()]];
}
return array;
}
std::vector<std::string> fromArray(NSArray<NSString*> * array)
{
std::vector<std::string> vec;
for (NSString * string in array)
{
vec.push_back([string UTF8String]);
}
return vec;
}
@implementation ZetaAuthorizationHelper
- (id)init
{
self = [super init];
if (self != nil)
{
shouldRun = true;
// Set up our XPC listener to handle requests on our Mach service.
self->_listener = [[NSXPCListener alloc] initWithMachServiceName:kHelperToolMachServiceName];
self->_listener.delegate = self;
}
return self;
}
- (void)run
{
// Tell the XPC listener to start processing requests.
[self.listener resume];
// Run the run loop until it's time to terminate.
bool runLoopSuccess = true;
while (shouldRun && runLoopSuccess)
{
runLoopSuccess = [[NSRunLoop mainRunLoop]
runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
}
}
- (void)stop
{
shouldRun = false;
[self.listener invalidate];
// Stop the run loop
CFRunLoopStop(CFRunLoopGetMain());
}
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
{
assert(listener == self.listener);
assert(newConnection != nil);
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ZetaAuthorizationHelperProtocol)];
newConnection.exportedObject = self;
[newConnection resume];
return YES;
}
NSError * checkAuthorization(NSData * authData, SEL command)
{
NSError * error = nil;
AuthorizationRef authRef = NULL;
assert(command != nil);
// First check that authData looks reasonable.
error = nil;
if ((authData == nil) || ([authData length] != sizeof(AuthorizationExternalForm)))
{
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:paramErr userInfo:nil];
return error;
}
// Create an authorization ref from that the external form data contained within.
auto extForm = static_cast<const AuthorizationExternalForm *>([authData bytes]);
OSStatus err = AuthorizationCreateFromExternalForm(extForm, &authRef);
// Authorize the right associated with the command.
if (err == errAuthorizationSuccess)
{
AuthorizationItem oneRight = { NULL, 0, NULL, 0 };
AuthorizationRights rights = { 1, &oneRight };
auto right = [CommonAuthorization authorizationRightForCommand:command];
if (!right)
{
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:paramErr userInfo:nil];
return error;
}
oneRight.name = [right UTF8String];
err = AuthorizationCopyRights(authRef, &rights, NULL,
kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed,
NULL);
}
if (err != errAuthorizationSuccess)
{
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil];
}
if (authRef != NULL)
{
OSStatus junk = AuthorizationFree(authRef, 0);
assert(junk == errAuthorizationSuccess);
}
return error;
}
- (void)getVersionWithReply:(void (^)(NSError * error, NSString *))reply
{
reply(nil, [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]);
}
// Checks authorization, and handles c++ exceptions by forwarding them to the
// caller.
template<typename C, typename R>
void processWithExceptionForwarding(NSData * authData, SEL command,
R reply, C callable)
{
NSError * error = checkAuthorization(authData, command);
if (error)
{
reply(error);
return;
}
try
{
callable();
}
catch (std::exception const & e)
{
reply([NSError errorWithDomain:@"ZFSException" code:-1 userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithUTF8String:e.what()]}]);
}
}
- (void)stopHelperWithAuthorization:(NSData *)authData
withReply:(void (^)(NSError *))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
// Acknowledge receipt of stop request, performed asyncronously
reply(nullptr);
[self stop];
});
}
- (void)importPools:(NSDictionary *)importData authorization:(NSData *)authData
withReply:(void (^)(NSError *))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
std::vector<std::string> failures;
NSNumber * pool = [importData objectForKey:@"poolGUID"];
zfs::LibZFSHandle::ImportProps props;
if (id ar = [importData objectForKey:@"altroot"])
props.altroot.assign([ar UTF8String]);
if (id aidm = [importData objectForKey:@"allowHostIDMismatch"])
props.allowHostIDMismatch = [aidm boolValue];
if (id auh = [importData objectForKey:@"allowUnhealthy"])
props.allowUnhealthy = [auh boolValue];
if (id ro = [importData objectForKey:@"readOnly"])
props.readOnly = [ro boolValue];
if (id spo = [importData objectForKey:@"searchPathOverride"])
props.searchPathOverride = fromArray(spo);
std::vector<zfs::ZPool> importedPools;
zfs::LibZFSHandle zfs;
if (pool != nil)
{
importedPools.emplace_back(zfs.import([pool unsignedLongLongValue], props));
}
else
{
importedPools = zfs.importAllPools(props);
}
if (failures.empty())
{
reply(nullptr);
}
else
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:
formatForHumans(failures).c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
}
});
}
- (void)importablePools:(NSDictionary *)importData
authorization:(NSData *)authData
withReply:(void (^)(NSError *, NSArray *))reply
{
NSError * error = checkAuthorization(authData, _cmd);
if (error)
{
reply(error, nullptr);
return;
}
try
{
zfs::LibZFSHandle zfs;
std::vector<std::string> searchPathOverride;
if (id spo = [importData objectForKey:@"searchPathOverride"])
searchPathOverride = fromArray(spo);
auto pools = zfs.importablePools(searchPathOverride);
NSMutableArray * poolsArray = [[NSMutableArray alloc] initWithCapacity:pools.size()];
for (auto const & pool : pools)
{
NSString * name = [NSString stringWithUTF8String:pool.name.c_str()];
NSNumber * guid = [NSNumber numberWithUnsignedLongLong:pool.guid];
NSNumber * status = [NSNumber numberWithUnsignedLongLong:pool.status];
NSMutableArray<NSString*> * deviceArray = toArray(pool.devices);
NSDictionary * poolDict =
@{@"name": name, @"guid": guid, @"status": status, @"devices": deviceArray};
[poolsArray addObject:poolDict];
}
reply(nullptr, poolsArray);
}
catch (std::exception const & e)
{
reply([NSError errorWithDomain:@"ZFSException" code:-1 userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithUTF8String:e.what()]}], nullptr);
}
}
- (void)exportPools:(NSDictionary *)exportData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * poolName = [exportData objectForKey:@"pool"];
bool force = false;
if (id o = [exportData objectForKey:@"force"])
force = [o boolValue];
if (!poolName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto pool = zfs.pool(std::string(poolName.UTF8String));
// Export Pool
pool.exportPool(force);
reply(nullptr);
});
}
- (void)mountFilesystems:(NSDictionary *)mountData authorization:(NSData *)authData
withReply:(void (^)(NSError *))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * fsName = [mountData objectForKey:@"filesystem"];
bool recursive = false;
if (id o = [mountData objectForKey:@"recursive"])
recursive = [o boolValue];
if (!fsName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto fs = zfs.filesystem([fsName UTF8String]);
int ret = 0;
if (recursive)
ret = fs.mountRecursive();
else
ret = fs.mount();
if (ret == 0)
{
reply(nullptr);
}
else
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:
zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
}
});
}
- (void)unmountFilesystems:(NSDictionary *)mountData authorization:(NSData *)authData
withReply:(void (^)(NSError *))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * fsName = [mountData objectForKey:@"filesystem"];
bool force = false;
if (id o = [mountData objectForKey:@"force"])
force = [o boolValue];
bool recursive = false;
if (id o = [mountData objectForKey:@"recursive"])
recursive = [o boolValue];
if (!fsName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto fs = zfs.filesystem([fsName UTF8String]);
int ret = 0;
if (recursive)
ret = fs.unmountRecursive(force);
else
ret = fs.unmount();
if (ret == 0)
{
reply(nullptr);
}
else
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:
zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
}
});
}
- (void)snapshotFilesystem:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * fsName = [fsData objectForKey:@"filesystem"];
NSString * snapName = [fsData objectForKey:@"snapshot"];
bool recursive = false;
if (id o = [fsData objectForKey:@"recursive"])
recursive = [o boolValue];
if (!fsName || !snapName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto fs = zfs.filesystem([fsName UTF8String]);
auto ret = fs.snapshot([snapName UTF8String], recursive);
if (ret == 0)
{
reply(nullptr);
}
else
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
}
});
}
- (void)rollbackFilesystem:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * snapName = [fsData objectForKey:@"snapshot"];
bool force = false;
if (id o = [fsData objectForKey:@"force"])
force = [o boolValue];
if (!snapName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto snap = zfs.filesystem([snapName UTF8String]);
auto res = snap.rollback(force);
if (res == 0)
{
reply(nullptr);
}
else
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
}
});
}
- (void)cloneSnapshot:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * snapName = [fsData objectForKey:@"snapshot"];
NSString * newFSName = [fsData objectForKey:@"newFilesystem"];
if (!snapName || !newFSName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
std::string newFSNameStr = [newFSName UTF8String];
auto snap = zfs.filesystem([snapName UTF8String]);
if (snap.clone(newFSNameStr) == 0)
{
auto newFS = zfs.filesystem(newFSNameStr);
if (newFS.mount() == 0)
{
reply(nullptr);
return;
}
}
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
});
}
- (void)createFilesystem:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * newFSName = [fsData objectForKey:@"filesystem"];
NSString * mountpoint = [fsData objectForKey:@"mountpoint"];
if (!newFSName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
std::string newFSNameStr = [newFSName UTF8String];
std::string mountpointStr = mountpoint ? [mountpoint UTF8String] : "";
if (zfs.createFilesystem(newFSNameStr, mountpointStr) == 0)
{
auto newFS = zfs.filesystem(newFSNameStr);
if (newFS.mount() == 0)
{
reply(nullptr);
return;
}
}
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
});
}
- (void)createVolume:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * newFSName = [fsData objectForKey:@"filesystem"];
NSNumber * size = [fsData objectForKey:@"size"];
NSNumber * blocksize = [fsData objectForKey:@"blocksize"];
if (!newFSName || size == nullptr)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
std::string newFSNameStr = [newFSName UTF8String];
auto s = [size unsignedLongLongValue];
auto bs = blocksize != nullptr ? [blocksize unsignedLongLongValue] : 0;
if (zfs.createVolume(newFSNameStr, s, bs) == 0)
{
reply(nullptr);
return;
}
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
});
}
- (void)destroy:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * fsName = [fsData objectForKey:@"filesystem"];
bool recursive = false;
if (id o = [fsData objectForKey:@"recursive"])
recursive = [o boolValue];
bool force = false;
if (id o = [fsData objectForKey:@"force"])
force = [o boolValue];
if (!fsName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto fs = zfs.filesystem([fsName UTF8String]);
int ret = 0;
if (recursive)
{
ret = fs.destroyRecursive(force);
}
else
{
auto dependents = fs.dependents();
if (dependents.empty())
{
ret = fs.destroy(force);
}
else
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: @"Filesystem has Dependents"
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
return;
}
}
if (ret == 0)
{
reply(nullptr);
}
else
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
}
});
}
- (void)loadKeyForFilesystem:(NSDictionary *)loadData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * fsName = [loadData objectForKey:@"filesystem"];
NSString * key = [loadData objectForKey:@"key"];
if (!fsName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto fs = zfs.filesystem([fsName UTF8String]);
int ret = 0;
if (key)
{
ret = fs.loadKey([key UTF8String]);
}
else if (fs.keyLocation() == zfs::ZFileSystem::KeyLocation::uri)
{
ret = fs.loadKeyFile();
}
else
{
reply([NSError errorWithDomain:@"ZFSKeyError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Key"}]);
return;
}
if (ret)
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSKeyError" code:-1 userInfo:userInfo]);
return;
}
// Encryption Root Filesystem and contained filesystems recursively
ret = fs.automountRecursive();
if (ret)
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
}
reply(nullptr);
});
}
- (void)unloadKeyForFilesystem:(NSDictionary *)unloadData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * fsName = [unloadData objectForKey:@"filesystem"];
if (!fsName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto fs = zfs.filesystem([fsName UTF8String]);
auto ret = fs.unloadKey();
if (ret == 0)
{
reply(nullptr);
}
else
{
NSDictionary * userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithUTF8String:
zfs.lastError().c_str()]
};
reply([NSError errorWithDomain:@"ZFSError" code:-1 userInfo:userInfo]);
}
});
}
- (void)scrubPool:(NSDictionary *)poolData authorization:(NSData *)authData
withReply:(void (^)(NSError *))reply
{
processWithExceptionForwarding(authData, _cmd, reply, [=]()
{
NSString * poolName = [poolData objectForKey:@"pool"];
NSString * command = [poolData objectForKey:@"command"];
if (!poolName)
{
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Missing Arguments"}]);
return;
}
zfs::LibZFSHandle zfs;
auto pool = zfs.pool(std::string(poolName.UTF8String));
if (command)
{
if ([command isEqualToString:@"stop"])
pool.scrubStop();
else if ([command isEqualToString:@"pause"])
pool.scrubPause();
// No other commands are supported
else
reply([NSError errorWithDomain:@"ZFSArgError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Invalid Scrub Command"}]);
}
else
{
pool.scrub();
}
reply(nullptr);
});
}
@end
================================================
FILE: ZetaAuthorizationHelper/ZetaAuthorizationHelperProtocol.h
================================================
//
// ZetaAuthorizationHelperProtocol.h
// ZetaWatch
//
// Created by cbreak on 18.01.01.
// Copyright © 2018 the-color-black.net. All rights reserved.
//
#define kHelperToolMachServiceName @"net.the-color-black.ZetaAuthorizationHelper"
@protocol ZetaAuthorizationHelperProtocol
@required
- (void)getVersionWithReply:(void(^)(NSError * error, NSString * version))reply;
- (void)stopHelperWithAuthorization:(NSData *)authData
withReply:(void(^)(NSError * error))reply;
- (void)importPools:(NSDictionary *)importData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)importablePools:(NSDictionary *)importData authorization:(NSData*)authData withReply:(void(^)(NSError * error, NSArray * importablePools))reply;
- (void)exportPools:(NSDictionary *)exportData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)mountFilesystems:(NSDictionary *)mountData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)unmountFilesystems:(NSDictionary *)mountData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)snapshotFilesystem:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)rollbackFilesystem:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)cloneSnapshot:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)createFilesystem:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)createVolume:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)destroy:(NSDictionary *)fsData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)loadKeyForFilesystem:(NSDictionary *)loadData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)unloadKeyForFilesystem:(NSDictionary *)unloadData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
- (void)scrubPool:(NSDictionary *)poolData authorization:(NSData *)authData withReply:(void(^)(NSError * error))reply;
@end
================================================
FILE: ZetaAuthorizationHelper/ZetaCPPUtils.hpp
================================================
//
// ZetaCPPUtils.hpp
// ZetaWatch
//
// Created by cbreak on 19.07.28.
// Copyright © 2019 the-color-black.net. All rights reserved.
//
#ifndef ZetaCPPUtils_h
#define ZetaCPPUtils_h
#include "ZFSWrapper/ZFSUtils.hpp"
#include <vector>
#include <sstream>
template<typename T>
inline std::string formatForHumans(std::vector<T> const & things)
{
if (things.empty())
return std::string();
std::stringstream ss;
ss << things[0];
for (size_t i = 1; i < things.size(); ++i)
{
ss << ", " << things[i];
}
return ss.str();
}
#endif /* ZetaCPPUtils_h */
================================================
FILE: ZetaAuthorizationHelper/main.m
================================================
//
// main.m
// ZetaAuthorizationHelper
//
// Created by cbreak on 18.01.01.
// Copyright © 2018 the-color-black.net. All rights reserved.
//
#include "ZetaAuthorizationHelper.h"
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool
{
ZetaAuthorizationHelper * helper = [[ZetaAuthorizationHelper alloc] init];
[helper run];
}
return 0;
}
================================================
FILE: ZetaLoginItemHelper/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSBackgroundOnly</key>
<true/>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2021 the-color-black.net. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
================================================
FILE: ZetaLoginItemHelper/main.m
================================================
//
// main.m
// ZetaLoginItemHelper
//
// Created by cbreak on 19.11.02.
// Copyright © 2019 the-color-black.net. All rights reserved.
//
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[])
{
// Start the main ZetaWatch application
// This trampoline is needed since SMLoginItemSetEnabled only allows adding
// helpers to start at login, not the main bundle.
// see ZetaWatch/ZetaWatchDelegate.mm for the login item adding code
@autoreleasepool
{
// Start any ZetaWatch without adding a new instance
[[NSWorkspace sharedWorkspace]
launchAppWithBundleIdentifier:@"net.the-color-black.ZetaWatch"
options:NSWorkspaceLaunchDefault
additionalEventParamDescriptor:0
launchIdentifier:0];
}
// Don't exit since ServiceManagement doesn't like it
return NSApplicationMain(argc, argv);
}
================================================
FILE: ZetaWatch/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "Zetaicoon-16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "Zetaicoon-32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "Zetaicoon-32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "Zetaicoon-64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "Zetaicoon-128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "Zetaicoon-256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "Zetaicoon-256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "Zetaicoon-512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "Zetaicoon-512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "Zetaicoon-1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: ZetaWatch/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: ZetaWatch/Assets.xcassets/Zeta.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "Zetaicoon.pdf",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: ZetaWatch/Base.lproj/MainMenu.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" userLabel="ZetaWatchDelegate" customClass="ZetaWatchDelegate">
<connections>
<outlet property="authorization" destination="GUh-uV-dxo" id="989-1T-oct"/>
<outlet property="poolWatcher" destination="Gim-eq-VbR" id="l93-hb-HuX"/>
<outlet property="settings" destination="h6V-8x-hYX" id="nvs-pP-koq"/>
<outlet property="updater" destination="7Va-uZ-m1K" id="VUM-ji-fYM"/>
<outlet property="zetaConfirmDialog" destination="YY7-LW-cAD" id="N6U-3T-0X2"/>
<outlet property="zetaKeyLoader" destination="R7D-cp-kuE" id="Uml-Lc-GeC"/>
<outlet property="zetaMainMenu" destination="8rf-zp-5r9" id="20J-Sj-1ol"/>
<outlet property="zetaMenu" destination="Xld-Up-BZ8" id="YRA-tL-FBE"/>
<outlet property="zetaQueryDialog" destination="TB2-7Z-kJ2" id="d4N-Ym-SU3"/>
</connections>
</customObject>
<customObject id="8rf-zp-5r9" userLabel="ZetaMainMenu" customClass="ZetaMainMenu">
<connections>
<outlet property="_authorization" destination="GUh-uV-dxo" id="LTt-go-j7Z"/>
<outlet property="notificationCenter" destination="ZZj-pd-85j" id="DDy-Za-7rV"/>
<outlet property="poolWatcher" destination="Gim-eq-VbR" id="Sat-ah-3Qq"/>
<outlet property="zetaConfirmDialog" destination="YY7-LW-cAD" id="Yck-ti-hMt"/>
<outlet property="zetaKeyLoader" destination="R7D-cp-kuE" id="aMW-DQ-FcT"/>
<outlet property="zetaQueryDialog" destination="TB2-7Z-kJ2" id="F0s-lJ-1nh"/>
</connections>
</customObject>
<customObject id="geo-tu-CMM" userLabel="ZetaImportMenu" customClass="ZetaImportMenu">
<connections>
<outlet property="_authorization" destination="GUh-uV-dxo" id="Psx-ls-DeC"/>
<outlet property="autoImporter" destination="PVX-FU-gbc" id="Wpo-l0-uGC"/>
<outlet property="importMenu" destination="fE9-G4-NH4" id="jfo-ja-1Zj"/>
<outlet property="poolWatcher" destination="Gim-eq-VbR" id="aD3-N2-eyI"/>
</connections>
</customObject>
<customObject id="R7D-cp-kuE" userLabel="ZetaKeyLoader" customClass="ZetaKeyLoader">
<connections>
<outlet property="_authorization" destination="GUh-uV-dxo" id="j1a-fu-F0a"/>
<outlet property="loadButton" destination="Xth-17-Uyp" id="ShD-Rm-nkI"/>
<outlet property="passwordField" destination="JpZ-yq-Swt" id="wki-ew-pno"/>
<outlet property="poolWatcher" destination="Gim-eq-VbR" id="hdd-tK-37f"/>
<outlet property="popover" destination="5Lh-hG-dv8" id="bFc-sJ-D7x"/>
<outlet property="progressIndicator" destination="IW2-QV-nuy" id="1wo-S0-51q"/>
<outlet property="queryField" destination="vtC-BP-wc5" id="cQa-7q-bCw"/>
<outlet property="skipButton" destination="sXs-lU-vuw" id="jjX-d7-NRy"/>
<outlet property="statusField" destination="egb-Mb-iyZ" id="FbE-63-Kfl"/>
<outlet property="useKeychainCheckbox" destination="2s9-7L-bQq" id="6dw-gL-9v1"/>
</connections>
</customObject>
<customObject id="TB2-7Z-kJ2" userLabel="ZetaQueryDialog" customClass="ZetaQueryDialog">
<connections>
<outlet property="popover" destination="BNT-uI-e5Z" id="Yz7-Dw-vEz"/>
<outlet property="queryField" destination="VwX-rR-NXB" id="dK5-xq-IgY"/>
<outlet property="replyField" destination="aF4-gD-hTY" id="8bG-cA-Ey2"/>
</connections>
</customObject>
<customObject id="YY7-LW-cAD" userLabel="ZetaConfirmDialog" customClass="ZetaConfirmDialog">
<connections>
<outlet property="infoField" destination="KzI-U2-jrx" id="er4-6R-hpv"/>
<outlet property="popover" destination="n6f-GT-2V0" id="Qhx-3R-efB"/>
<outlet property="queryField" destination="Bjp-t2-sCZ" id="Arh-fc-VT8"/>
</connections>
</customObject>
<customObject id="Gim-eq-VbR" userLabel="ZetaPoolWatcher" customClass="ZetaPoolWatcher"/>
<customObject id="PVX-FU-gbc" userLabel="ZetaAutoImporter" customClass="ZetaAutoImporter">
<connections>
<outlet property="_authorization" destination="GUh-uV-dxo" id="hKw-Oj-ONj"/>
</connections>
</customObject>
<customObject id="ZZj-pd-85j" userLabel="ZetaNotificationCenter" customClass="ZetaNotificationCenter">
<connections>
<outlet property="poolWatcher" destination="Gim-eq-VbR" id="Lp3-zU-Amk"/>
</connections>
</customObject>
<customObject id="GUh-uV-dxo" userLabel="ZetaAuthorization" customClass="ZetaAuthorization">
<connections>
<outlet property="notificationCenter" destination="ZZj-pd-85j" id="TOz-7T-gp3"/>
</connections>
</customObject>
<menu title="Zeta" id="Xld-Up-BZ8">
<items>
<menuItem title="ZFS Pools" tag="100" hidden="YES" enabled="NO" id="SFT-8i-4hp">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="V2G-dn-yYW"/>
<menuItem title="Actions" tag="101" hidden="YES" enabled="NO" id="Wnr-ig-9x9">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Import Pool" id="bAG-Ud-NX6">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Import Pool" id="fE9-G4-NH4" userLabel="Import Pool Menu">
<connections>
<outlet property="delegate" destination="geo-tu-CMM" id="rbu-7n-mSX"/>
</connections>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="Ttd-8u-p8d"/>
<menuItem title="Settings" id="abZ-nP-vC5">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Settings" id="Zp5-as-Y5e">
<items>
<menuItem title="Use Keychain by default" id="orV-Zm-zgL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<binding destination="oMO-Og-s5N" name="value" keyPath="values.useKeychain" id="BYu-QP-V3e"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="M9f-nT-c4H"/>
<menuItem title="Auto-Import Pools" id="O0q-h1-njv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<binding destination="oMO-Og-s5N" name="value" keyPath="values.autoImport" id="LV6-2F-8fO"/>
</connections>
</menuItem>
<menuItem title="Auto-Unlock Datasets" id="1bo-el-qdg">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<binding destination="oMO-Og-s5N" name="value" keyPath="values.autoUnlock" id="sSC-4i-zjn"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="k2v-Lw-Y2t"/>
<menuItem title="Start at Login" id="WkG-Hl-jeI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<binding destination="oMO-Og-s5N" name="value" keyPath="values.startAtLogin" id="Vwc-yO-K6u"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="wz1-YY-4Wk"/>
<menuItem title="Auto Update" id="PuO-P5-LRP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<binding destination="7Va-uZ-m1K" name="value" keyPath="automaticallyChecksForUpdates" id="cJl-aO-zqY"/>
</connections>
</menuItem>
<menuItem title="Check for Updates now..." id="e40-VT-eEj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="checkForUpdates:" target="7Va-uZ-m1K" id="yj1-Ju-zDX"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="438-n3-d29"/>
<menuItem title="More Settings..." id="2HR-5O-7CX">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="showSettings:" target="Voe-Tx-rLC" id="5H4-tn-qq1"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="ZkL-mf-Ahh"/>
<menuItem title="Quit" id="PuA-D0-otp">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="terminate:" target="-2" id="L56-LL-ZV3"/>
</connections>
</menuItem>
</items>
<connections>
<outlet property="delegate" destination="8rf-zp-5r9" id="L78-mK-psa"/>
</connections>
<point key="canvasLocation" x="132" y="183"/>
</menu>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="ZetaWatch" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="ZetaWatch" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About ZetaWatch" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide ZetaWatch" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit ZetaWatch" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" id="KaW-ft-85H">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="-1" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="jxT-CU-nIS">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
<items>
<menuItem title="Font" id="Gi5-1S-RQB">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq"/>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27"/>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq"/>
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
<connections>
<action selector="underline:" target="-1" id="FYS-2b-JAY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL"/>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST"/>
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
<menuItem title="Kern" id="jBQ-r6-VK2">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
<items>
<menuItem title="Use Default" id="GUa-eO-cwY">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/>
</connections>
</menuItem>
<menuItem title="Use None" id="cDB-IK-hbR">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="46P-cB-AYj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="ogc-rX-tC1">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="o6e-r0-MWq">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
<items>
<menuItem title="Use Default" id="agt-UL-0e3">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/>
</connections>
</menuItem>
<menuItem title="Use None" id="J7y-lM-qPV">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/>
</connections>
</menuItem>
<menuItem title="Use All" id="xQD-1f-W4t">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="OaQ-X3-Vso">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
<items>
<menuItem title="Use Default" id="3Om-Ey-2VK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="-1" id="0vZ-95-Ywn"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="Rqc-34-cIF">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="-1" id="3qV-fo-wpU"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="I0S-gh-46l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="-1" id="Q6W-4W-IGz"/>
</connections>
</menuItem>
<menuItem title="Raise" id="2h7-ER-AoG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/>
</connections>
</menuItem>
<menuItem title="Lower" id="1tx-W0-xDw">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
<connections>
<action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="-1" id="GJO-xA-L4q"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="-1" id="JfD-CL-leO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="Fal-I4-PZk">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="d9c-me-L2H">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
<connections>
<action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
<connections>
<action selector="alignCenter:" target="-1" id="spX-mk-kcS"/>
</connections>
</menuItem>
<menuItem title="Justify" id="J5U-5w-g23">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="-1" id="ljL-7U-jND"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
<connections>
<action selector="alignRight:" target="-1" id="r48-bG-YeY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
<menuItem title="Writing Direction" id="H1b-Si-o9J">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
<items>
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="YGs-j5-SAR">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/>
</connections>
</menuItem>
<menuItem id="Lbh-J2-qVU">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/>
</connections>
</menuItem>
<menuItem id="jFq-tB-4Kx">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="Nop-cj-93Q">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/>
</connections>
</menuItem>
<menuItem id="BgM-ve-c93">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/>
</connections>
</menuItem>
<menuItem id="RB4-Sm-HuC">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
<menuItem title="Show Ruler" id="vLm-3I-IUL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="-1" id="71i-fW-3W2"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="ZetaWatch Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="159" y="1264"/>
</menu>
<customView id="40L-u9-aeI" userLabel="PasswordDialog">
<rect key="frame" x="0.0" y="0.0" width="555" height="134"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<secureTextField verticalHuggingPriority="750" verticalCompressionResistancePriority="751" translatesAutoresizingMaskIntoConstraints="NO" id="JpZ-yq-Swt">
<rect key="frame" x="92" y="68" width="443" height="21"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="nB2-dg-ZrZ">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
<connections>
<action selector="loadKey:" target="R7D-cp-kuE" id="Wfm-Ep-xcX"/>
</connections>
</secureTextFieldCell>
</secureTextField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vtC-BP-wc5">
<rect key="frame" x="90" y="97" width="447" height="17"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="17" id="J3h-Ms-Ygd"/>
</constraints>
<textFieldCell key="cell" refusesFirstResponder="YES" title="Enter the password for %@" id="zNZ-X6-NWc">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="249" verticalHuggingPriority="750" verticalCompressionResistancePriority="752" translatesAutoresizingMaskIntoConstraints="NO" id="egb-Mb-iyZ">
<rect key="frame" x="114" y="22" width="277" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Status" id="Mwk-R6-lED">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<progressIndicator wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="IW2-QV-nuy">
<rect key="frame" x="92" y="22" width="16" height="16"/>
</progressIndicator>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Xth-17-Uyp">
<rect key="frame" x="458" y="32" width="83" height="32"/>
<buttonCell key="cell" type="push" title="Unlock" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="piW-QM-gQc">
<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="loadKey:" target="R7D-cp-kuE" id="062-OO-Y0n"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="sXs-lU-vuw">
<rect key="frame" x="391" y="32" width="67" height="32"/>
<buttonCell key="cell" type="push" title="Skip" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="vVt-vK-kZ4">
<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="skipFileSystem:" target="R7D-cp-kuE" id="HLD-XO-u4Y"/>
</connections>
</button>
<button horizontalHuggingPriority="249" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2s9-7L-bQq">
<rect key="frame" x="90" y="44" width="301" height="18"/>
<buttonCell key="cell" type="check" title="Store in Keychain" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="sK3-hH-Yef">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="LRH-QE-iBn">
<rect key="frame" x="20" y="50" width="64" height="64"/>
<constraints>
<constraint firstAttribute="height" constant="64" id="TDZ-YV-zW0"/>
<constraint firstAttribute="width" constant="64" id="x8p-su-1N7"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSApplicationIcon" id="qon-SO-Jhf"/>
</imageView>
</subviews>
<constraints>
<constraint firstItem="2s9-7L-bQq" firstAttribute="leading" secondItem="vtC-BP-wc5" secondAttribute="leading" id="00p-YA-u2F"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="sXs-lU-vuw" secondAttribute="bottom" constant="20" symbolic="YES" id="0VA-kp-xSZ"/>
<constraint firstAttribute="trailing" secondItem="Xth-17-Uyp" secondAttribute="trailing" constant="20" symbolic="YES" id="1cC-Nw-Mpg"/>
<constraint firstItem="vtC-BP-wc5" firstAttribute="leading" secondItem="LRH-QE-iBn" secondAttribute="trailing" constant="8" symbolic="YES" id="1gu-dR-bQA"/>
<constraint firstItem="IW2-QV-nuy" firstAttribute="leading" secondItem="vtC-BP-wc5" secondAttribute="leading" id="2Yw-EI-3P1"/>
<constraint firstItem="LRH-QE-iBn" firstAttribute="leading" secondItem="40L-u9-aeI" secondAttribute="leading" constant="20" symbolic="YES" id="8Ld-Ru-1X8"/>
<constraint firstItem="vtC-BP-wc5" firstAttribute="top" secondItem="40L-u9-aeI" secondAttribute="top" priority="750" constant="20" symbolic="YES" id="AfF-td-1Z6"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="Xth-17-Uyp" secondAttribute="bottom" constant="20" symbolic="YES" id="KPl-GI-4YV"/>
<constraint firstItem="2s9-7L-bQq" firstAttribute="top" secondItem="JpZ-yq-Swt" secondAttribute="bottom" constant="8" symbolic="YES" id="Mef-as-LYH"/>
<constraint firstItem="egb-Mb-iyZ" firstAttribute="leading" secondItem="IW2-QV-nuy" secondAttribute="trailing" constant="8" symbolic="YES" id="Nl8-ra-JyC"/>
<constraint firstItem="Xth-17-Uyp" firstAttribute="top" secondItem="JpZ-yq-Swt" secondAttribute="bottom" constant="8" symbolic="YES" id="P47-oI-yFJ"/>
<constraint firstItem="Xth-17-Uyp" firstAttribute="leading" secondItem="sXs-lU-vuw" secondAttribute="trailing" constant="12" symbolic="YES" id="XSz-Lh-EYu"/>
<constraint firstItem="IW2-QV-nuy" firstAttribute="top" secondItem="2s9-7L-bQq" secondAttribute="bottom" constant="8" symbolic="YES" id="ZPU-AH-PdX"/>
<constraint firstItem="JpZ-yq-Swt" firstAttribute="top" secondItem="vtC-BP-wc5" secondAttribute="bottom" constant="8" symbolic="YES" id="abq-QG-ftd"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="egb-Mb-iyZ" secondAttribute="bottom" constant="20" symbolic="YES" id="emi-Ch-eys"/>
<constraint firstItem="sXs-lU-vuw" firstAttribute="leading" secondItem="2s9-7L-bQq" secondAttribute="trailing" constant="8" symbolic="YES" id="hSW-tq-jqR"/>
<constraint firstItem="egb-Mb-iyZ" firstAttribute="top" secondItem="2s9-7L-bQq" secondAttribute="bottom" constant="8" symbolic="YES" id="l8W-4p-UJX"/>
<constraint firstItem="sXs-lU-vuw" firstAttribute="leading" secondItem="egb-Mb-iyZ" secondAttribute="trailing" constant="8" symbolic="YES" id="tdT-So-PUO"/>
<constraint firstItem="JpZ-yq-Swt" firstAttribute="leading" secondItem="vtC-BP-wc5" secondAttribute="leading" id="tqi-ow-0BQ"/>
<constraint firstItem="LRH-QE-iBn" firstAttribute="top" secondItem="40L-u9-aeI" secondAttribute="top" constant="20" symbolic="YES" id="u0N-kd-ick"/>
<constraint firstAttribute="trailing" secondItem="JpZ-yq-Swt" secondAttribute="trailing" constant="20" id="xXA-Ui-KUB"/>
<constraint firstItem="sXs-lU-vuw" firstAttribute="top" secondItem="JpZ-yq-Swt" secondAttribute="bottom" constant="8" symbolic="YES" id="yUJ-Wh-FsI"/>
<constraint firstAttribute="trailing" secondItem="vtC-BP-wc5" secondAttribute="trailing" constant="20" symbolic="YES" id="ziC-dL-Eus"/>
</constraints>
<connections>
<outlet property="nextKeyView" destination="JpZ-yq-Swt" id="djn-Eh-4Qs"/>
</connections>
<point key="canvasLocation" x="145" y="510"/>
</customView>
<viewController id="3wl-p9-tQW" userLabel="Password Popover View Controller">
<connections>
<outlet property="view" destination="40L-u9-aeI" id="SJp-sP-WqY"/>
</connections>
</viewController>
<popover behavior="semitransient" id="5Lh-hG-dv8" userLabel="Password Popover">
<connections>
<outlet property="contentViewController" destination="3wl-p9-tQW" id="3c9-rd-q9f"/>
<outlet property="delegate" destination="R7D-cp-kuE" id="4kg-JY-FmY"/>
</connections>
</popover>
<viewController id="cvg-uB-4z4" userLabel="Query Popover View Controller">
<connections>
<outlet property="view" destination="xBy-DS-Zxq" id="boV-oP-ybM"/>
</connections>
</viewController>
<popover behavior="semitransient" id="BNT-uI-e5Z" userLabel="Query Popover">
<connections>
<outlet property="contentViewController" destination="cvg-uB-4z4" id="ihh-qg-O93"/>
</connections>
</popover>
<viewController id="6oG-mj-9NA" userLabel="Confirm View Controller">
<connections>
<outlet property="view" destination="sBQ-2t-b2A" id="1oL-R8-65K"/>
</connections>
</viewController>
<popover id="n6f-GT-2V0" userLabel="Confirm Popover">
<connections>
<outlet property="contentViewController" destination="6oG-mj-9NA" id="YDZ-xj-0gV"/>
</connections>
</popover>
<userDefaultsController representsSharedInstance="YES" id="oMO-Og-s5N"/>
<customObject id="7Va-uZ-m1K" customClass="SUUpdater"/>
<customView id="xBy-DS-Zxq" userLabel="QueryDialog">
<rect key="frame" x="0.0" y="0.0" width="555" height="115"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="VwX-rR-NXB" userLabel="QueryTextField">
<rect key="frame" x="90" y="78" width="447" height="17"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="17" id="bI6-0C-vUT"/>
</constraints>
<textFieldCell key="cell" refusesFirstResponder="YES" title="Query" id="qSb-DF-62v">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="975-gg-tbR">
<rect key="frame" x="484" y="13" width="57" height="32"/>
<buttonCell key="cell" type="push" title="Ok" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="4cM-PF-O9d">
<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="TB2-7Z-kJ2" id="rNC-zb-KEI"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7YP-fB-fKc">
<rect key="frame" x="402" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="fsa-Sc-vN6">
<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="TB2-7Z-kJ2" id="MnW-9i-IFa"/>
</connections>
</button>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="flA-4i-OSt">
<rect key="frame" x="20" y="31" width="64" height="64"/>
<constraints>
<constraint firstAttribute="width" constant="64" id="Wbu-ja-J2J"/>
<constraint firstAttribute="height" constant="64" id="hnI-ca-3jH"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSApplicationIcon" id="mfz-8D-mnE"/>
</imageView>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aF4-gD-hTY">
<rect key="frame" x="92" y="49" width="443" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="ztY-kw-Z07">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="flA-4i-OSt" firstAttribute="leading" secondItem="xBy-DS-Zxq" secondAttribute="leading" constant="20" symbolic="YES" id="5Y2-Cs-uzD"/>
<constraint firstItem="975-gg-tbR" firstAttribute="top" secondItem="aF4-gD-hTY" secondAttribute="bottom" constant="8" symbolic="YES" id="6bj-Ds-15S"/>
<constraint firstItem="7YP-fB-fKc" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="aF4-gD-hTY" secondAttribute="leading" id="C7M-q4-fHe"/>
<constraint firstAttribute="bottom" secondItem="975-gg-tbR" secondAttribute="bottom" constant="20" symbolic="YES" id="GqB-xX-tBM"/>
<constraint firstItem="flA-4i-OSt" firstAttribute="top" secondItem="xBy-DS-Zxq" secondAttribute="top" constant="20" symbolic="YES" id="L38-PC-unr"/>
<constraint firstAttribute="trailing" secondItem="aF4-gD-hTY" secondAttribute="trailing" constant="20" symbolic="YES" id="Q90-Fo-k83"/>
<constraint firstAttribute="trailing" secondItem="975-gg-tbR" secondAttribute="trailing" constant="20" symbolic="YES" id="ViS-af-HY5"/>
<constraint firstAttribute="trailing" secondItem="VwX-rR-NXB" secondAttribute="trailing" constant="20" symbolic="YES" id="a5q-sl-5GT"/>
<constraint firstItem="975-gg-tbR" firstAttribute="leading" secondItem="7YP-fB-fKc" secondAttribute="trailing" constant="12" symbolic="YES" id="aYI-j7-vek"/>
<constraint firstItem="aF4-gD-hTY" firstAttribute="leading" secondItem="VwX-rR-NXB" secondAttribute="leading" id="acM-8z-O5p"/>
<constraint firstItem="VwX-rR-NXB" firstAttribute="leading" secondItem="flA-4i-OSt" secondAttribute="trailing" constant="8" symbolic="YES" id="hiA-RE-dVE"/>
<constraint firstItem="aF4-gD-hTY" firstAttribute="top" secondItem="VwX-rR-NXB" secondAttribute="bottom" constant="8" id="lTK-Kf-8of"/>
<constraint firstItem="7YP-fB-fKc" firstAttribute="top" secondItem="aF4-gD-hTY" secondAttribute="bottom" constant="8" symbolic="YES" id="s41-PV-p6O"/>
<constraint firstItem="VwX-rR-NXB" firstAttribute="top" secondItem="xBy-DS-Zxq" secondAttribute="top" priority="750" constant="20" symbolic="YES" id="zMj-zA-y4l"/>
</constraints>
<point key="canvasLocation" x="144.5" y="732"/>
</customView>
<customView id="sBQ-2t-b2A" userLabel="ConfirmationDialog">
<rect key="frame" x="0.0" y="0.0" width="555" height="272"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="ksH-SQ-feV">
<rect key="frame" x="20" y="188" width="64" height="64"/>
<constraints>
<constraint firstAttribute="width" constant="64" id="SYz-2n-tdp"/>
<constraint firstAttribute="height" constant="64" id="cbC-aV-dbT"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSApplicationIcon" id="jGe-fX-ycL"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bjp-t2-sCZ" userLabel="QueryTextField">
<rect key="frame" x="90" y="235" width="447" height="17"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="17" id="YhE-iC-0mY"/>
</constraints>
<textFieldCell key="cell" refusesFirstResponder="YES" title="Query" id="D6G-X2-Ubq">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="KzI-U2-jrx">
<rect key="frame" x="92" y="61" width="443" height="166"/>
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" selectable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="9lS-cc-3KX">
<font key="font" metaFont="message" size="11"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="j4u-aq-qhY">
<rect key="frame" x="484" y="13" width="57" height="32"/>
<buttonCell key="cell" type="push" title="Ok" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="CUl-rd-k52">
<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="YY7-LW-cAD" id="YEn-e2-lYC"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FAa-ai-LRq">
<rect key="frame" x="402" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ldU-dB-OJf">
<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="YY7-LW-cAD" id="yno-up-e0z"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="KzI-U2-jrx" firstAttribute="top" secondItem="Bjp-t2-sCZ" secondAttribute="bottom" constant="8" symbolic="YES" id="0CO-b4-7l4"/>
<constraint firstItem="Bjp-t2-sCZ" firstAttribute="top" secondItem="sBQ-2t-b2A" secondAttribute="top" constant="20" symbolic="YES" id="20o-E8-Ue7"/>
<constraint firstItem="KzI-U2-jrx" firstAttribute="trailing" secondItem="j4u-aq-qhY" secondAttribute="trailing" id="6Pu-s7-W1c"/>
<constraint firstItem="ksH-SQ-feV" firstAttribute="top" secondItem="sBQ-2t-b2A" secondAttribute="top" constant="20" symbolic="YES" id="9yf-4D-dCy"/>
<constraint firstAttribute="bottom" secondItem="j4u-aq-qhY" secondAttribute="bottom" constant="20" symbolic="YES" id="FwY-zg-B0k"/>
<constraint firstAttribute="trailing" secondItem="Bjp-t2-sCZ" secondAttribute="trailing" constant="20" symbolic="YES" id="LYY-tf-Xcn"/>
<constraint firstItem="Bjp-t2-sCZ" firstAttribute="leading" secondItem="ksH-SQ-feV" secondAttribute="trailing" constant="8" symbolic="YES" id="M3d-bq-AkO"/>
<constraint firstItem="j4u-aq-qhY" firstAttribute="leading" secondItem="FAa-ai-LRq" secondAttribute="trailing" constant="12" symbolic="YES" id="XcM-SV-Ej8"/>
<constraint firstItem="FAa-ai-LRq" firstAttribute="top" secondItem="KzI-U2-jrx" secondAttribute="bottom" constant="20" symbolic="YES" id="am7-vv-7qp"/>
<constraint firstItem="j4u-aq-qhY" firstAttribute="top" secondItem="KzI-U2-jrx" secondAttribute="bottom" constant="20" symbolic="YES" id="b04-dC-BUg"/>
<constraint firstAttribute="trailing" secondItem="j4u-aq-qhY" secondAttribute="trailing" constant="20" symbolic="YES" id="cXN-99-Ft9"/>
<constraint firstItem="ksH-SQ-feV" firstAttribute="leading" secondItem="sBQ-2t-b2A" secondAttribute="leading" constant="20" symbolic="YES" id="veU-Ix-P9F"/>
<constraint firstItem="FAa-ai-LRq" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="ksH-SQ-feV" secondAttribute="trailing" constant="8" symbolic="YES" id="yiD-9F-pJN"/>
<constraint firstItem="KzI-U2-jrx" firstAttribute="leading" secondItem="ksH-SQ-feV" secondAttribute="trailing" constant="8" symbolic="YES" id="zGA-kB-ZnU"/>
</constraints>
<point key="canvasLocation" x="144.5" y="1063"/>
</customView>
<viewController id="wow-Hy-QXj" userLabel="Settings View Controller">
<connections>
<outlet property="view" destination="lzX-XA-XzO" id="QzI-Ao-jyd"/>
</connections>
</viewController>
<popover behavior="t" id="h6V-8x-hYX" userLabel="Settings">
<connections>
<outlet property="contentViewController" destination="wow-Hy-QXj" id="Iba-Pd-Csq"/>
</connections>
</popover>
<view id="lzX-XA-XzO" userLabel="SettingsView">
<rect key="frame" x="0.0" y="0.0" width="563" height="178"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<pathControl verticalHuggingPriority="750" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3QB-P7-si2">
<rect key="frame" x="116" y="14" width="430" height="25"/>
<pathCell key="cell" selectable="YES" editable="YES" alignment="left" placeholderString="Default Mountpoint" pathStyle="popUp" id="tfh-lb-I0Y">
<font key="font" metaFont="system"/>
<url key="url" string="file:///Volumes/"/>
<allowedTypes>
<string>public.folder</string>
</allowedTypes>
<connections>
<binding destination="oMO-Og-s5N" name="value" keyPath="values.defaultAltroot" id="O5x-Zo-nGc">
<dictionary key="options">
<string key="NSValueTransformerName">PathValueTransformer</string>
</dictionary>
</binding>
</connections>
</pathCell>
</pathControl>
<button horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="O5K-Z7-VRD">
<rect key="frame" x="18" y="18" width="95" height="18"/>
<buttonCell key="cell" type="check" title="Use Altroot:" bezelStyle="regularSquare" imagePosition="left" inset="2" id="cbb-cy-BJO">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
<connections>
<binding destination="oMO-Og-s5N" name="value" keyPath="values.useAltroot" id="xMN-cB-aSW"/>
</connections>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="owe-My-lsx">
<rect key="frame" x="18" y="38" width="527" height="18"/>
<buttonCell key="cell" type="check" title="Keep awake during Scrub" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="dX7-Wx-70H">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
<connections>
<binding destination="oMO-Og-s5N" name="value" keyPath="values.keepAwakeDuringScrub" id="mgD-hN-TIk"/>
</connections>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Pt1-2o-MSz">
<rect key="frame" x="18" y="58" width="527" height="18"/>
<buttonCell key="cell" type="check" title="Allow host id mismatch" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="GxS-Vj-BcC">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
<connections>
<binding destination="oMO-Og-s5N" name="value" keyPath="values.allowHostIDMismatch" id="Dns-nF-r7O"/>
</connections>
</buttonCell>
</button>
<scrollView verticalHuggingPriority="200" verticalCompressionResistancePriority="1000" autohidesScrollers="YES" horizontalLineScroll="22" horizontalPageScroll="10" verticalLineScroll="22" verticalPageScroll="10" usesPredominantAxisScrolling="NO" verticalScrollElasticity="allowed" translatesAutoresizingMaskIntoConstraints="NO" id="qzi-84-8Hb">
<rect key="frame" x="20" y="82" width="523" height="76"/>
<clipView key="contentView" ambiguous="YES" id="fKK-4M-wy0">
<rect key="frame" x="1" y="0.0" width="521" height="75"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="20" rowSizeStyle="automatic" headerView="8kc-tN-1kV" viewBased="YES" floatsGroupRows="NO" id="Op4-MF-bkS">
<rect key="frame" x="0.0" y="0.0" width="521" height="50"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<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 width="518" minWidth="40" maxWidth="1000" id="xU7-mk-oli">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Search Path">
<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" title="Text Cell" id="fAD-76-93W">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="eD7-n2-0Ve">
<rect key="frame" x="1" y="1" width="518" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<pathControl verticalHuggingPriority="750" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0aW-al-p9r">
<rect key="frame" x="2" y="0.0" width="496" height="20"/>
<pathCell key="cell" controlSize="small" selectable="YES" alignment="left" id="5dc-aU-BGm">
<font key="font" metaFont="smallSystem"/>
<url key="url" string="file://localhost/Applications/"/>
</pathCell>
<connections>
<binding destination="eD7-n2-0Ve" name="value" keyPath="objectValue" id="Nal-1Z-Efh">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<bool key="NSConditionallySetsEnabled" value="NO"/>
<string key="NSValueTransformerName">PathValueTransformer</string>
</dictionary>
</binding>
</connections>
</pathControl>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="0aW-al-p9r" secondAttribute="trailing" constant="20" symbolic="YES" id="MJu-VA-Vk7"/>
<constraint firstItem="0aW-al-p9r" firstAttribute="leading" secondItem="eD7-n2-0Ve" secondAttribute="leading" constant="2" id="MVD-8c-nqY"/>
<constraint firstAttribute="bottom" secondItem="0aW-al-p9r" secondAttribute="bottom" id="UiB-2d-Zxj"/>
<constraint firstItem="0aW-al-p9r" firstAttribute="top" secondItem="eD7-n2-0Ve" secondAttribute="top" id="vk8-tQ-CiF"/>
</constraints>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<binding destination="JiR-wc-2kO" name="content" keyPath="arrangedObjects" id="xc3-po-ZOI"/>
<binding destination="JiR-wc-2kO" name="selectionIndexes" keyPath="selectionIndexes" previousBinding="xc3-po-ZOI" id="6B1-9o-UpY"/>
</connections>
</tableView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="64" id="s8e-Sk-EIe"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="enK-Gr-bvp">
<rect key="frame" x="1" y="118" width="238" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="vG5-V5-ygO">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="8kc-tN-1kV">
<rect key="frame" x="0.0" y="0.0" width="521" height="25"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
</subviews>
<constraints>
<constraint firstItem="Pt1-2o-MSz" firstAttribute="top" secondItem="qzi-84-8Hb" secondAttribute="bottom" constant="8" symbolic="YES" id="3dG-kN-FVm"/>
<constraint firstAttribute="bottom" secondItem="O5K-Z7-VRD" secondAttribute="bottom" constant="20" symbolic="YES" id="CHT-u3-7ne"/>
<constraint firstItem="owe-My-lsx" firstAttribute="leading" secondItem="O5K-Z7-VRD" secondAttribute="leading" id="FYT-Pg-8s0"/>
<constraint firstAttribute="trailing" secondItem="Pt1-2o-MSz" secondAttribute="trailing" constant="20" symbolic="YES" id="Hlb-0P-HXl"/>
<constraint firstAttribute="trailing" secondItem="qzi-84-8Hb" secondAttribute="trailing" constant="20" symbolic="YES" id="KPS-Wl-ZNb"/>
<constraint firstAttribute="trailing" secondItem="owe-My-lsx" secondAttribute="trailing" constant="20" symbolic="YES" id="SFA-sa-jNk"/>
<constraint firstItem="O5K-Z7-VRD" firstAttribute="top" secondItem="owe-My-lsx" secondAttribute="bottom" constant="6" symbolic="YES" id="T5M-wM-ZpK"/>
<constraint firstItem="qzi-84-8Hb" firstAttribute="top" secondItem="lzX-XA-XzO" secondAttribute="top" constant="20" symbolic="YES" id="Tuz-OK-yTc"/>
<constraint firstItem="3QB-P7-si2" firstAttribute="leading" secondItem="O5K-Z7-VRD" secondAttribute="trailing" constant="8" symbolic="YES" id="csk-OS-mva"/>
<constraint firstItem="owe-My-lsx" firstAttribute="top" secondItem="Pt1-2o-MSz" secondAttribute="bottom" constant="6" symbolic="YES" id="dc1-XQ-HyI"/>
<constraint firstItem="3QB-P7-si2" firstAttribute="firstBaseline" secondItem="O5K-Z7-VRD" secondAttribute="firstBaseline" id="j1W-kM-lY5"/>
<constraint firstItem="owe-My-lsx" firstAttribute="leading" secondItem="lzX-XA-XzO" secondAttribute="leading" constant="20" symbolic="YES" id="mhR-Hz-n9N"/>
<constraint firstItem="qzi-84-8Hb" firstAttribute="leading" secondItem="lzX-XA-XzO" secondAttribute="leading" constant="20" symbolic="YES" id="mmv-DP-j88"/>
<constraint firstItem="Pt1-2o-MSz" firstAttribute="leading" secondItem="lzX-XA-XzO" secondAttribute="leading" constant="20" symbolic="YES" id="nyW-Kp-F2F"/>
<constraint firstAttribute="trailing" secondItem="3QB-P7-si2" secondAttribute="trailing" constant="20" symbolic="YES" id="x30-HK-XS1"/>
</constraints>
<point key="canvasLocation" x="144.5" y="1491"/>
</view>
<arrayController objectClassName="NSMutableString" automaticallyPreparesContent="YES" id="JiR-wc-2kO" userLabel="SearchPathOverride Controller">
<connections>
<binding destination="oMO-Og-s5N" name="contentArray" keyPath="values.searchPathOverride" id="0CQ-4D-uxB">
<dictionary key="options">
<bool key="NSConditionallySetsEditable" value="NO"/>
<bool key="NSDeletesObjectsOnRemove" value="YES"/>
<bool key="NSHandlesContentAsCompoundValue" value="YES"/>
</dictionary>
</binding>
</connections>
</arrayController>
</objects>
<resources>
<image name="NSApplicationIcon" width="32" height="32"/>
</resources>
</document>
================================================
FILE: ZetaWatch/Base.lproj/NewFS.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ZetaDictQueryDialog">
<connections>
<outlet property="popover" destination="0wU-rJ-gHT" id="RJA-Wc-e5P"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Y1R-F4-349" userLabel="NewFSDialog">
<rect key="frame" x="0.0" y="0.0" width="555" height="148"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1dp-Iq-Zlw" userLabel="QueryTextField">
<rect key="frame" x="90" y="111" width="447" height="17"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="17" id="Jtk-1e-ewV"/>
</constraints>
<textFieldCell key="cell" refusesFirstResponder="YES" title="Create new filesystem:" id="PO3-tn-mgG">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tDb-2y-bDq">
<rect key="frame" x="484" y="13" width="57" height="32"/>
<buttonCell key="cell" type="push" title="Ok" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="fN5-5d-JCF">
<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="HPd-GH-Mi8"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="j9L-jr-sWA">
<rect key="frame" x="402" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="RPy-h3-YWQ">
<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="oGC-62-njg"/>
</connections>
</button>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="7yl-N2-YqW">
<rect key="frame" x="20" y="64" width="64" height="64"/>
<constraints>
<constraint firstAttribute="height" constant="64" id="994-r0-jca"/>
<constraint firstAttribute="width" constant="64" id="JZ6-vK-bzz"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSApplicationIcon" id="ZYf-0t-nIl"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FNR-fj-4rT">
<rect key="frame" x="90" y="84" width="44" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Name:" id="dZr-UM-kGp">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="i54-l9-xMh">
<rect key="frame" x="174" y="81" width="361" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="Name" drawsBackground="YES" id="Gxt-2u-LZb">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="value" keyPath="self.queryDict.filesystem" id="dra-gB-sxT">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
<bool key="NSValidatesImmediately" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TtX-Ig-20c">
<rect key="frame" x="90" y="52" width="78" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Mountpoint:" id="suq-Kc-sjY">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lsr-yr-QsN">
<rect key="frame" x="174" y="49" width="361" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="Mountpoint" drawsBackground="YES" id="haT-1t-5JI">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="value" keyPath="self.queryDict.mountpoint" id="ozk-Rv-kNc">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
<bool key="NSValidatesImmediately" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstItem="7yl-N2-YqW" firstAttribute="top" secondItem="Y1R-F4-349" secondAttribute="top" constant="20" symbolic="YES" id="1jM-pH-zzz"/>
<constraint firstItem="tDb-2y-bDq" firstAttribute="leading" secondItem="j9L-jr-sWA" secondAttribute="trailing" constant="12" symbolic="YES" id="26k-uY-ND8"/>
<constraint firstAttribute="bottom" secondItem="tDb-2y-bDq" secondAttribute="bottom" constant="20" symbolic="YES" id="8IT-Vz-RIq"/>
<constraint firstItem="tDb-2y-bDq" firstAttribute="top" secondItem="lsr-yr-QsN" secondAttribute="bottom" constant="8" symbolic="YES" id="BDj-Xj-yEc"/>
<constraint firstItem="lsr-yr-QsN" firstAttribute="leading" secondItem="TtX-Ig-20c" secondAttribute="trailing" constant="8" symbolic="YES" id="BOS-Lq-Yc6"/>
<constraint firstItem="7yl-N2-YqW" firstAttribute="leading" secondItem="Y1R-F4-349" secondAttribute="leading" constant="20" symbolic="YES" id="Ced-2V-BMV"/>
<constraint firstAttribute="trailing" secondItem="i54-l9-xMh" secondAttribute="trailing" constant="20" symbolic="YES" id="E4M-nK-fQg"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="top" secondItem="1dp-Iq-Zlw" secondAttribute="bottom" constant="8" symbolic="YES" id="Jcn-xO-1hQ"/>
<constraint firstAttribute="trailing" secondItem="tDb-2y-bDq" secondAttribute="trailing" constant="20" symbolic="YES" id="KvF-fC-8kz"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FNR-fj-4rT" secondAttribute="trailing" constant="8" symbolic="YES" id="L0W-yB-dlg"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="trailing" secondItem="lsr-yr-QsN" secondAttribute="trailing" id="LGA-pH-jY3"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="leading" secondItem="lsr-yr-QsN" secondAttribute="leading" id="Q3W-vn-0mb"/>
<constraint firstItem="FNR-fj-4rT" firstAttribute="leading" secondItem="1dp-Iq-Zlw" secondAttribute="leading" id="ad7-mz-DrS"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="firstBaseline" secondItem="FNR-fj-4rT" secondAttribute="firstBaseline" id="gYn-yp-NRz"/>
<constraint firstItem="1dp-Iq-Zlw" firstAttribute="leading" secondItem="7yl-N2-YqW" secondAttribute="trailing" constant="8" symbolic="YES" id="h8e-AX-oaa"/>
<constraint firstItem="FNR-fj-4rT" firstAttribute="leading" secondItem="TtX-Ig-20c" secondAttribute="leading" id="ic1-wn-oiH"/>
<constraint firstAttribute="trailing" secondItem="1dp-Iq-Zlw" secondAttribute="trailing" constant="20" symbolic="YES" id="jXH-th-x2x"/>
<constraint firstItem="j9L-jr-sWA" firstAttribute="firstBaseline" secondItem="tDb-2y-bDq" secondAttribute="firstBaseline" id="mGb-j2-POm"/>
<constraint firstItem="lsr-yr-QsN" firstAttribute="top" secondItem="i54-l9-xMh" secondAttribute="bottom" constant="10" symbolic="YES" id="nfG-pr-GUW"/>
<constraint firstItem="j9L-jr-sWA" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Y1R-F4-349" secondAttribute="leading" constant="20" symbolic="YES" id="pSw-8x-TM7"/>
<constraint firstItem="1dp-Iq-Zlw" firstAttribute="top" secondItem="Y1R-F4-349" secondAttribute="top" priority="750" constant="20" symbolic="YES" id="sD8-QV-07k"/>
<constraint firstItem="TtX-Ig-20c" firstAttribute="firstBaseline" secondItem="lsr-yr-QsN" secondAttribute="firstBaseline" id="x23-1c-w5i"/>
</constraints>
<point key="canvasLocation" x="815" y="748"/>
</customView>
<userDefaultsController representsSharedInstance="YES" id="7zF-te-Tq6"/>
<viewController id="Xpw-zj-uOl" userLabel="NewFS Popover View Controller">
<connections>
<outlet property="view" destination="Y1R-F4-349" id="DWH-F2-RhI"/>
</connections>
</viewController>
<popover id="0wU-rJ-gHT" userLabel="NewFS Popover">
<connections>
<outlet property="contentViewController" destination="Xpw-zj-uOl" id="cnk-CD-wG3"/>
</connections>
</popover>
</objects>
<resources>
<image name="NSApplicationIcon" width="128" height="128"/>
</resources>
</document>
================================================
FILE: ZetaWatch/Base.lproj/NewVol.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="ZetaDictQueryDialog">
<connections>
<outlet property="popover" destination="0wU-rJ-gHT" id="RJA-Wc-e5P"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Y1R-F4-349" userLabel="NewVolDialog">
<rect key="frame" x="0.0" y="0.0" width="555" height="180"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1dp-Iq-Zlw" userLabel="QueryTextField">
<rect key="frame" x="90" y="143" width="447" height="17"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="17" id="Jtk-1e-ewV"/>
</constraints>
<textFieldCell key="cell" refusesFirstResponder="YES" title="Create new volume:" id="PO3-tn-mgG">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tDb-2y-bDq">
<rect key="frame" x="484" y="13" width="57" height="32"/>
<buttonCell key="cell" type="push" title="Ok" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="fN5-5d-JCF">
<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="HPd-GH-Mi8"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="j9L-jr-sWA">
<rect key="frame" x="402" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="RPy-h3-YWQ">
<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="oGC-62-njg"/>
</connections>
</button>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="7yl-N2-YqW">
<rect key="frame" x="20" y="96" width="64" height="64"/>
<constraints>
<constraint firstAttribute="height" constant="64" id="994-r0-jca"/>
<constraint firstAttribute="width" constant="64" id="JZ6-vK-bzz"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSApplicationIcon" id="ZYf-0t-nIl"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="FNR-fj-4rT">
<rect key="frame" x="90" y="116" width="65" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Name:" id="dZr-UM-kGp">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="i54-l9-xMh">
<rect key="frame" x="161" y="113" width="374" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="Name" drawsBackground="YES" id="Gxt-2u-LZb">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="value" keyPath="self.queryDict.filesystem" id="dra-gB-sxT">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
<bool key="NSValidatesImmediately" value="YES"/>
</dictionary>
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TtX-Ig-20c">
<rect key="frame" x="90" y="84" width="65" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Size:" id="suq-Kc-sjY">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lsr-yr-QsN">
<rect key="frame" x="161" y="81" width="374" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="Size" drawsBackground="YES" id="haT-1t-5JI">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="value" keyPath="self.queryDict.size" id="FBg-vF-o8l">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
<bool key="NSValidatesImmediately" value="YES"/>
<string key="NSValueTransformerName">SizeTransformer</string>
</dictionary>
</binding>
</connections>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Uvx-B3-kFr">
<rect key="frame" x="161" y="49" width="374" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" title="Blocksize" drawsBackground="YES" id="51K-lm-Qe9">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="value" keyPath="self.queryDict.blocksize" id="Bg9-ia-qLS">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
<bool key="NSValidatesImmediately" value="YES"/>
<string key="NSValueTransformerName">SizeTransformer</string>
</dictionary>
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ns6-44-PQg">
<rect key="frame" x="90" y="52" width="65" height="17"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Blocksize:" id="ZNp-jl-N5X">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="Uvx-B3-kFr" firstAttribute="leading" secondItem="Ns6-44-PQg" secondAttribute="trailing" constant="8" id="018-Wy-Y1j"/>
<constraint firstItem="7yl-N2-YqW" firstAttribute="top" secondItem="Y1R-F4-349" secondAttribute="top" constant="20" symbolic="YES" id="1jM-pH-zzz"/>
<constraint firstItem="tDb-2y-bDq" firstAttribute="leading" secondItem="j9L-jr-sWA" secondAttribute="trailing" constant="12" symbolic="YES" id="26k-uY-ND8"/>
<constraint firstItem="Ns6-44-PQg" firstAttribute="firstBaseline" secondItem="Uvx-B3-kFr" secondAttribute="firstBaseline" id="77h-b7-F2G"/>
<constraint firstAttribute="bottom" secondItem="tDb-2y-bDq" secondAttribute="bottom" constant="20" symbolic="YES" id="8IT-Vz-RIq"/>
<constraint firstItem="lsr-yr-QsN" firstAttribute="leading" secondItem="TtX-Ig-20c" secondAttribute="trailing" constant="8" symbolic="YES" id="BOS-Lq-Yc6"/>
<constraint firstItem="7yl-N2-YqW" firstAttribute="leading" secondItem="Y1R-F4-349" secondAttribute="leading" constant="20" symbolic="YES" id="Ced-2V-BMV"/>
<constraint firstAttribute="trailing" secondItem="i54-l9-xMh" secondAttribute="trailing" constant="20" symbolic="YES" id="E4M-nK-fQg"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="top" secondItem="1dp-Iq-Zlw" secondAttribute="bottom" constant="8" symbolic="YES" id="Jcn-xO-1hQ"/>
<constraint firstAttribute="trailing" secondItem="tDb-2y-bDq" secondAttribute="trailing" constant="20" symbolic="YES" id="KvF-fC-8kz"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="leading" secondItem="FNR-fj-4rT" secondAttribute="trailing" constant="8" symbolic="YES" id="L0W-yB-dlg"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="trailing" secondItem="lsr-yr-QsN" secondAttribute="trailing" id="LGA-pH-jY3"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="leading" secondItem="lsr-yr-QsN" secondAttribute="leading" id="Q3W-vn-0mb"/>
<constraint firstItem="Uvx-B3-kFr" firstAttribute="top" secondItem="lsr-yr-QsN" secondAttribute="bottom" constant="10" id="YFf-2D-EH1"/>
<constraint firstItem="FNR-fj-4rT" firstAttribute="leading" secondItem="1dp-Iq-Zlw" secondAttribute="leading" id="ad7-mz-DrS"/>
<constraint firstItem="i54-l9-xMh" firstAttribute="firstBaseline" secondItem="FNR-fj-4rT" secondAttribute="firstBaseline" id="gYn-yp-NRz"/>
<constraint firstItem="1dp-Iq-Zlw" firstAttribute="leading" secondItem="7yl-N2-YqW" secondAttribute="trailing" constant="8" symbolic="YES" id="h8e-AX-oaa"/>
<constraint firstItem="FNR-fj-4rT" firstAttribute="leading" secondItem="TtX-Ig-20c" secondAttribute="leading" id="ic1-wn-oiH"/>
<constraint firstAttribute="trailing" secondItem="1dp-Iq-Zlw" secondAttribute="trailing" constant="20" symbolic="YES" id="jXH-th-x2x"/>
<constraint firstItem="Uvx-B3-kFr" firstAttribute="leading" secondItem="lsr-yr-QsN" secondAttribute="leading" id="kIp-Z6-T5e"/>
<constraint firstItem="j9L-jr-sWA" firstAttribute="firstBaseline" secondItem="tDb-2y-bDq" secondAttribute="firstBaseline" id="mGb-j2-POm"/>
<constraint firstItem="Ns6-44-PQg" firstAttribute="leading" secondItem="TtX-Ig-20c" secondAttribute="leading" id="nDd-qO-w6y"/>
<constraint firstItem="lsr-yr-QsN" firstAttribute="top" secondItem="i54-l9-xMh" secondAttribute="bottom" constant="10" symbolic="YES" id="nfG-pr-GUW"/>
<constraint firstItem="j9L-jr-sWA" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Y1R-F4-349" secondAttribute="leading" constant="20" symbolic="YES" id="pSw-8x-TM7"/>
<constraint firstItem="1dp-Iq-Zlw" firstAttribute="top" secondItem="Y1R-F4-349" secondAttribute="top" priority="750" constant="20" symbolic="YES" id="sD8-QV-07k"/>
<constraint firstItem="tDb-2y-bDq" firstAttribute="top" secondItem="Uvx-B3-kFr" secondAttribute="bottom" constant="8" symbolic="YES" id="tOu-Yr-4f2"/>
<constraint firstItem="Uvx-B3-kFr" firstAttribute="trailing" secondItem="lsr-yr-QsN" secondAttribute="trailing" id="vqP-u8-1Ud"/>
<constraint firstItem="TtX-Ig-20c" firstAttribute="firstBaseline" secondItem="lsr-yr-QsN" secondAttribute="firstBaseline" id="x23-1c-w5i"/>
</constraints>
<point key="canvasLocation" x="814.5" y="769.5"/>
</customView>
<userDefaultsController representsSharedInstance="YES" id="7zF-te-Tq6"/>
<viewController id="Xpw-zj-uOl" userLabel="NewFS Popover View Controller">
<connections>
<outlet property="view" destination="Y1R-F4-349" id="DWH-F2-RhI"/>
</connections>
</viewController>
<popover id="0wU-rJ-gHT" userLabel="NewFS Popover">
<connections>
<outlet property="contentViewController" destination="Xpw-zj-uOl" id="cnk-CD-wG3"/>
</connections>
</popover>
</objects>
<resources>
<image name="NSApplicationIcon" width="128" height="128"/>
</resources>
</document>
================================================
FILE: ZetaWatch/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(ZETA_VERSION)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(ZETA_VERSION)</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSBackgroundOnly</key>
<false/>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>LSUIElement</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2021 the-color-black.net. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSUSerNotificationAlertStyle</key>
<string>alert</string>
<key>SMPrivilegedExecutables</key>
<dict>
<key>net.the-color-black.ZetaAuthorizationHelper</key>
<string>anchor apple generic and identifier "net.the-color-black.ZetaAuthorizationHelper" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = "8THUW5GT6P")</string>
</dict>
<key>SUFeedURL</key>
<string>https://zetawatch.the-color-black.net/download/2.1/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>Ed/JNtoVf4G8CX7qffgoFFHmb4303SFsmJ3yh2vAhyc=</string>
</dict>
</plist>
================================================
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationDispatcher.cpp
================================================
//
// IDDiskArbitrationDispatcher.cpp
// InvariantDisks
//
// Created by Gerhard Röthlin on 2014.04.27.
// Copyright (c) 2014 the-color-black.net. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the conditions of the "3-Clause BSD" license described in the BSD.LICENSE file are met.
// Additional licensing options are described in the README file.
//
#include "IDDiskArbitrationDispatcher.hpp"
#include "IDDiskArbitrationHandler.hpp"
#include "IDDiskArbitrationUtils.hpp"
#include <DiskArbitration/DiskArbitration.h>
#include <thread>
#include <vector>
#include <algorithm>
namespace ID
{
struct DiskArbitrationDispatcher::Impl
{
std::mutex mutex;
std::vector<Handler> handler;
DASessionRef session = nullptr;
bool scheduled = false;
};
DiskArbitrationDispatcher::DiskArbitrationDispatcher() :
m_impl(new Impl)
{
m_impl->session = DASessionCreate(kCFAllocatorDefault);
DARegisterDiskAppearedCallback(m_impl->session, nullptr, [](DADiskRef disk, void * ctx)
{ static_cast<DiskArbitrationDispatcher*>(ctx)->diskAppeared(disk); }, this);
DARegisterDiskDisappearedCallback(m_impl->session, nullptr, [](DADiskRef disk, void * ctx)
{ static_cast<DiskArbitrationDispatcher*>(ctx)->diskDisappeared(disk); }, this);
}
DiskArbitrationDispatcher::~DiskArbitrationDispatcher()
{
stop();
CFRelease(m_impl->session);
}
void DiskArbitrationDispatcher::addHandler(Handler handler)
{
std::lock_guard<std::mutex> lock(m_impl->mutex);
m_impl->handler.push_back(std::move(handler));
}
void DiskArbitrationDispatcher::removeHandler(Handler const & handler)
{
std::lock_guard<std::mutex> lock(m_impl->mutex);
m_impl->handler.erase(std::find(m_impl->handler.begin(), m_impl->handler.end(), handler),
m_impl->handler.end());
}
void DiskArbitrationDispatcher::clearHandler()
{
std::lock_guard<std::mutex> lock(m_impl->mutex);
m_impl->handler.clear();
}
void DiskArbitrationDispatcher::start()
{
std::lock_guard<std::mutex> lock(m_impl->mutex);
if (!m_impl->scheduled)
{
DASessionScheduleWithRunLoop(m_impl->session,
CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
m_impl->scheduled = true;
}
}
void DiskArbitrationDispatcher::stop()
{
std::lock_guard<std::mutex> lock(m_impl->mutex);
if (m_impl->scheduled)
{
DASessionUnscheduleFromRunLoop(m_impl->session,
CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
m_impl->scheduled = false;
}
}
void DiskArbitrationDispatcher::diskAppeared(DADiskRef disk) const
{
DiskInformation info = getDiskInformation(disk);
std::lock_guard<std::mutex> lock(m_impl->mutex);
for (auto const & handler: m_impl->handler)
handler->diskAppeared(disk, info);
}
void DiskArbitrationDispatcher::diskDisappeared(DADiskRef disk) const
{
DiskInformation info = getDiskInformation(disk);
std::lock_guard<std::mutex> lock(m_impl->mutex);
for (auto const & handler: m_impl->handler)
handler->diskDisappeared(disk, info);
}
}
================================================
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationDispatcher.hpp
================================================
//
// IDDiskArbitrationDispatcher.hpp
// InvariantDisks
//
// Created by Gerhard Röthlin on 2014.04.27.
// Copyright (c) 2014 the-color-black.net. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the conditions of the "3-Clause BSD" license described in the BSD.LICENSE file are met.
// Additional licensing options are described in the README file.
//
#ifndef ID_DISKARBITRATIONDISPATCHER_HPP
#define ID_DISKARBITRATIONDISPATCHER_HPP
#include <DiskArbitration/DADisk.h>
#include <memory>
namespace ID
{
class DiskArbitrationHandler;
/*!
\brief Dispatches DiskArbitration events, wrapper around the DiskArbitration framework
*/
class DiskArbitrationDispatcher
{
public:
typedef std::shared_ptr<DiskArbitrationHandler> Handler;
public:
DiskArbitrationDispatcher();
~DiskArbitrationDispatcher();
public:
void addHandler(Handler handler);
void removeHandler(Handler const & handler);
void clearHandler();
public:
void start();
void stop();
private:
void diskAppeared(DADiskRef disk) const;
void diskDisappeared(DADiskRef disk) const;
private:
struct Impl;
std::unique_ptr<Impl> m_impl;
};
}
#endif
================================================
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationHandler.hpp
================================================
//
// IDDiskArbitrationHandler.hpp
// InvariantDisks
//
// Created by Gerhard Röthlin on 2014.04.27.
// Copyright (c) 2014 the-color-black.net. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the conditions of the "3-Clause BSD" license described in the BSD.LICENSE file are met.
// Additional licensing options are described in the README file.
//
#ifndef ID_DISKARBITRATIONHANDLER_HPP
#define ID_DISKARBITRATIONHANDLER_HPP
#include <DiskArbitration/DADisk.h>
namespace ID
{
class DiskInformation;
class DiskArbitrationHandler
{
public:
explicit DiskArbitrationHandler() {}
virtual ~DiskArbitrationHandler() = default;
public:
virtual void diskAppeared(DADiskRef disk, DiskInformation const & info) = 0;
virtual void diskDisappeared(DADiskRef disk, DiskInformation const & info) = 0;
};
}
#endif
================================================
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationUtils.cpp
================================================
//
// IDDiskArbitrationUtils.cpp
// InvariantDisks
//
// Created by Gerhard Röthlin on 2014.04.27.
// Copyright (c) 2014 the-color-black.net. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the conditions of the "3-Clause BSD" license described in the BSD.LICENSE file are met.
// Additional licensing options are described in the README file.
//
#include "IDDiskArbitrationUtils.hpp"
#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
#include <sstream>
namespace ID
{
std::ostream & operator<<(std::ostream & os, DADiskRef disk)
{
return os << getDiskInformation(disk);
}
std::ostream & operator<<(std::ostream & os, DiskInformation const & disk)
{
return os << "Disk: (\n"
<< "\tVolumeKind=\"" << disk.volumeKind << "\"\n"
<< "\tVolumeUUID=\"" << disk.volumeUUID << "\"\n"
<< "\tVolumeName=\"" << disk.volumeName << "\"\n"
<< "\tVolumePath=\"" << disk.volumePath << "\"\n"
<< "\tMediaKind=\"" << disk.mediaKind << "\"\n"
<< "\tMediaType=\"" << disk.mediaType << "\"\n"
<< "\tMediaUUID=\"" << disk.mediaUUID << "\"\n"
<< "\tMediaBSDName=\"" << disk.mediaBSDName << "\"\n"
<< "\tMediaName=\"" << disk.mediaName << "\"\n"
<< "\tMediaPath=\"" << disk.mediaPath << "\"\n"
<< "\tMediaContent=\"" << disk.mediaContent << "\"\n"
<< "\tMedia(Whole,Leaf,Writable)=(" << disk.mediaWhole << ", "
<< disk.mediaLeaf << ", " << disk.mediaWritable << ")\n"
<< "\tDeviceGUID=\"" << disk.deviceGUID << "\"\n"
<< "\tDevicePath=\"" << disk.devicePath << "\"\n"
<< "\tDeviceProtocol=\"" << disk.deviceProtocol << "\"\n"
<< "\tDeviceModel=\"" << disk.deviceModel << "\"\n"
<< "\tBusName=\"" << disk.busName << "\"\n"
<< "\tBusPath=\"" << disk.busPath << "\"\n"
<< "\tIOSerial=\"" << disk.ioSerial << "\"\n"
<< "\tImagePath=\"" << disk.imagePath << "\"\n"
<< ")";
}
std::string to_string(CFStringRef str)
{
std::string result;
CFRange strRange = CFRangeMake(0, CFStringGetLength(str));
CFIndex strBytes = 0;
CFStringGetBytes(str, strRange, kCFStringEncodingUTF8, 0, false, nullptr, 0, &strBytes);
if (strBytes > 0)
{
result.resize(static_cast<size_t>(strBytes), '\0');
CFStringGetBytes(str, strRange, kCFStringEncodingUTF8, 0, false,
reinterpret_cast<UInt8*>(&result[0]), strBytes, nullptr);
}
return result;
}
std::string to_string(CFURLRef url)
{
CFStringRef str = CFURLCopyPath(url);
std::string result = to_string(str);
CFRelease(str);
return result;
}
std::string to_string(CFDataRef data)
{
char const * bytesBegin = reinterpret_cast<char const *>(CFDataGetBytePtr(data));
char const * bytesEnd = bytesBegin + CFDataGetLength(data);
std::stringstream ss;
ss << std::hex;
for (char const * byteIt = bytesBegin; byteIt != bytesEnd; ++byteIt)
ss << static_cast<unsigned>(*byteIt);
return ss.str();
}
std::string to_string(CFUUIDRef uuid)
{
CFStringRef str = CFUUIDCreateString(kCFAllocatorDefault, uuid);
std::string result = to_string(str);
CFRelease(str);
return result;
}
std::string to_string(CFTypeRef variant)
{
if (!variant)
return std::string();
CFTypeID typeID = CFGetTypeID(variant);
if (typeID == CFStringGetTypeID())
return to_string(CFStringRef(variant));
else if (typeID == CFURLGetTypeID())
return to_string(CFURLRef(variant));
else if (typeID == CFDataGetTypeID())
return to_string(CFDataRef(variant));
else if (typeID == CFUUIDGetTypeID())
return to_string(CFUUIDRef(variant));
return std::string();
}
std::string interpret_as_string(CFDataRef data)
{
char const * bytesBegin = reinterpret_cast<char const *>(CFDataGetBytePtr(data));
char const * bytesEnd = bytesBegin + CFDataGetLength(data);
return std::string(bytesBegin, bytesEnd);
}
template<typename T>
std::string stringFromDictionary(CFDictionaryRef dict, CFStringRef key)
{
if (T value = static_cast<T>(CFDictionaryGetValue(dict, key)))
return to_string(value);
return std::string();
}
int64_t numberFromDictionary(CFDictionaryRef dict, CFStringRef key)
{
if (CFNumberRef value = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, key)))
{
int64_t number = 0;
CFNumberGetValue(value, kCFNumberSInt64Type, &number);
return number;
}
return 0;
}
bool boolFromDictionary(CFDictionaryRef dict, CFStringRef key)
{
if (CFBooleanRef value = static_cast<CFBooleanRef>(CFDictionaryGetValue(dict, key)))
{
return CFBooleanGetValue(value);
}
return false;
}
std::string stringFromIOObjectWithParents(io_object_t ioObject, CFStringRef key)
{
std::string result;
CFTypeRef resultRef = IORegistryEntrySearchCFProperty(ioObject, kIOServicePlane, key,
kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
if (resultRef)
{
result = to_string(resultRef);
CFRelease(resultRef);
}
return result;
}
std::string serialNumberFromIOObject(io_object_t ioObject)
{
static CFStringRef const serialStrings[] = {
CFSTR("Serial Number"),
CFSTR("INQUIRY Unit Serial Number"),
CFSTR("USB Serial Number")
};
for (CFStringRef serialString: serialStrings)
{
std::string serial = stringFromIOObjectWithParents(ioObject, serialString);
if (!serial.empty())
return serial;
}
return std::string();
}
std::string imagePathFromIOObject(io_object_t ioObject)
{
std::string path;
CFStringRef key = CFSTR("image-path");
CFTypeRef resultRef = IORegistryEntrySearchCFProperty(ioObject, kIOServicePlane, key,
kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
if (resultRef)
{
if (CFGetTypeID(resultRef) == CFDataGetTypeID())
{
CFDataRef resultDataRef = CFDataRef(resultRef);
path = interpret_as_string(resultDataRef);
}
CFRelease(resultRef);
}
return path;
}
static std::string coreStorageMark = "/CoreStoragePhysical/";
DiskInformation getDiskInformation(DADiskRef disk)
{
DiskInformation info;
// DiskArbitration
CFDictionaryRef descDict = DADiskCopyDescription(disk);
if (!descDict)
return info;
info.volumeKind = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionVolumeKindKey);
info.volumeUUID = stringFromDictionary<CFUUIDRef>(descDict, kDADiskDescriptionVolumeUUIDKey);
info.volumeName = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionVolumeNameKey);
info.volumePath = stringFromDictionary<CFURLRef>(descDict, kDADiskDescriptionVolumePathKey);
info.mediaKind = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaKindKey);
info.mediaType = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaTypeKey);
info.mediaUUID = stringFromDictionary<CFUUIDRef>(descDict, kDADiskDescriptionMediaUUIDKey);
info.mediaBSDName = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaBSDNameKey);
info.mediaName = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaNameKey);
info.mediaPath = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaPathKey);
info.mediaContent = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionMediaContentKey);
info.mediaWhole = boolFromDictionary(descDict, kDADiskDescriptionMediaWholeKey);
info.mediaLeaf = boolFromDictionary(descDict, kDADiskDescriptionMediaLeafKey);
info.mediaWritable = boolFromDictionary(descDict, kDADiskDescriptionMediaWritableKey);
info.deviceGUID = stringFromDictionary<CFDataRef>(descDict, kDADiskDescriptionDeviceGUIDKey);
info.devicePath = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionDevicePathKey);
info.deviceProtocol = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionDeviceProtocolKey);
info.deviceModel = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionDeviceModelKey);
info.busName = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionBusNameKey);
info.busPath = stringFromDictionary<CFStringRef>(descDict, kDADiskDescriptionBusPathKey);
CFRelease(descDict);
// IOKit
io_service_t io = DADiskCopyIOMedia(disk);
info.ioSerial = serialNumberFromIOObject(io);
info.imagePath = imagePathFromIOObject(io);
CFMutableDictionaryRef ioDict = nullptr;
if (IORegistryEntryCreateCFProperties(io, &ioDict, kCFAllocatorDefault, 0) == kIOReturnSuccess)
{
// TODO: Pick out useful IOKit properties
CFRelease(ioDict);
}
IOObjectRelease(io);
// Guess wether this is an actual device
bool isCoreStorage = info.mediaPath.find(coreStorageMark) != std::string::npos;
bool isVirtual = info.deviceProtocol == kIOPropertyPhysicalInterconnectTypeVirtual;
info.isDevice = !isCoreStorage && !isVirtual;
return info;
}
bool isDevice(DiskInformation const & di)
{
return di.isDevice;
}
bool isWhole(DiskInformation const & di)
{
return di.mediaWhole;
}
std::string partitionSuffix(DiskInformation const & di)
{
if (!isWhole(di))
{
size_t suffixStart = di.mediaBSDName.find_last_not_of("0123456789");
if (suffixStart != std::string::npos &&
suffixStart+1 < di.mediaBSDName.size() &&
di.mediaBSDName[suffixStart] == 's')
{
return ':' + di.mediaBSDName.substr(suffixStart+1);
}
}
return std::string();
}
}
================================================
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationUtils.hpp
================================================
//
// IDDiskArbitrationUtils.hpp
// InvariantDisks
//
// Created by Gerhard Röthlin on 2014.04.27.
// Copyright (c) 2014 the-color-black.net. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the conditions of the "3-Clause BSD" license described in the BSD.LICENSE file are met.
// Additional licensing options are described in the README file.
//
#ifndef ID_DISKARBITRATIONUTILS_HPP
#define ID_DISKARBITRATIONUTILS_HPP
#include <DiskArbitration/DiskArbitration.h>
#include <iostream>
#include <string>
namespace ID
{
struct DiskInformation
{
std::string volumeKind;
std::string volumeUUID;
std::string volumeName;
std::string volumePath;
std::string mediaKind;
std::string mediaType;
std::string mediaUUID;
std::string mediaBSDName;
std::string mediaName;
std::string mediaPath;
std::string mediaContent;
bool isDevice;
bool mediaWhole;
bool mediaLeaf;
bool mediaWritable;
std::string deviceGUID;
std::string devicePath;
std::string deviceProtocol;
std::string deviceModel;
std::string busName;
std::string busPath;
std::string ioSerial;
std::string imagePath;
};
DiskInformation getDiskInformation(DADiskRef disk);
bool isDevice(DiskInformation const & di);
bool isWhole(DiskInformation const & di);
std::string partitionSuffix(DiskInformation const & di);
std::ostream & operator<<(std::ostream & os, DADiskRef disk);
std::ostream & operator<<(std::ostream & os, DiskInformation const & disk);
}
#endif
================================================
FILE: ZetaWatch/PathValueTransformer.m
================================================
//
// PathValueTransformer.m
// ZetaWatch
//
// Created by cbreak on 19.11.08.
// Copyright © 2019 the-color-black.net. All rights reserved.
//
#import <Foundation/Foundation.h>
/*!
\brief Transforms a path URL into a string and back, used for value binding
from a xib file.
*/
@interface PathValueTransformer : NSValueTransformer
@end
@implementation PathValueTransformer
+ (Class)transformedValueClass
{
return [NSString class];
}
+ (BOOL)allowsReverseTransformation
{
return YES;
}
- (id)transformedValue:(id)value
{
NSString * string = value;
return [NSURL URLWithString:string];
}
- (id)reverseTransformedValue:(id)value
{
NSURL * url = value;
return [url path];
}
- (void)initialize
{
if (self == [PathValueTransformer self])
{
PathValueTransformer * transformer = [[PathValueTransformer alloc] init];
[NSValueTransformer setValueTransformer:transformer
forName:@"PathValueTransformer"];
}
}
@end
================================================
FILE: ZetaWatch/SizeTransformer.mm
================================================
//
// SizeTransformer.m
// ZetaWatch
//
// Created by cbreak on 19.11.08.
// Copyright © 2019 the-color-black.net. All rights reserved.
//
#import <Foundation/Foundation.h>
#include "ZetaFormatHelpers.hpp"
/*!
\brief Transforms between a string and a byte number, used for value binding
from a xib file.
*/
@interface SizeTransformer : NSValueTransformer
@end
@implementation SizeTransformer
+ (Class)trans
gitextract_u2m5ltbd/ ├── .gitignore ├── .gitmodules ├── CommonAuthorization/ │ ├── CommonAuthorization.h │ ├── CommonAuthorization.m │ └── CommonAuthorization.strings ├── LICENSE.md ├── README.md ├── ZetaAuthorizationHelper/ │ ├── Info.plist │ ├── Launchd.plist │ ├── ZetaAuthorizationHelper.h │ ├── ZetaAuthorizationHelper.mm │ ├── ZetaAuthorizationHelperProtocol.h │ ├── ZetaCPPUtils.hpp │ └── main.m ├── ZetaLoginItemHelper/ │ ├── Info.plist │ └── main.m ├── ZetaWatch/ │ ├── Assets.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── Zeta.imageset/ │ │ └── Contents.json │ ├── Base.lproj/ │ │ ├── Localizable.strings │ │ ├── MainMenu.xib │ │ ├── NewFS.xib │ │ └── NewVol.xib │ ├── Info.plist │ ├── InvariantDisks/ │ │ ├── IDDiskArbitrationDispatcher.cpp │ │ ├── IDDiskArbitrationDispatcher.hpp │ │ ├── IDDiskArbitrationHandler.hpp │ │ ├── IDDiskArbitrationUtils.cpp │ │ └── IDDiskArbitrationUtils.hpp │ ├── PathValueTransformer.m │ ├── SizeTransformer.mm │ ├── ZetaAuthorization.h │ ├── ZetaAuthorization.mm │ ├── ZetaAutoImporter.h │ ├── ZetaAutoImporter.mm │ ├── ZetaBookmarkMenu.h │ ├── ZetaBookmarkMenu.mm │ ├── ZetaCommanderBase.h │ ├── ZetaCommanderBase.mm │ ├── ZetaConfirmDialog.h │ ├── ZetaConfirmDialog.mm │ ├── ZetaDictQueryDialog.h │ ├── ZetaDictQueryDialog.mm │ ├── ZetaFileSystemPropertyMenu.h │ ├── ZetaFileSystemPropertyMenu.mm │ ├── ZetaFormatHelpers.cpp │ ├── ZetaFormatHelpers.hpp │ ├── ZetaImportMenu.h │ ├── ZetaImportMenu.mm │ ├── ZetaKeyLoader.h │ ├── ZetaKeyLoader.mm │ ├── ZetaMainMenu.h │ ├── ZetaMainMenu.mm │ ├── ZetaNotificationCenter.h │ ├── ZetaNotificationCenter.mm │ ├── ZetaPoolPropertyMenu.h │ ├── ZetaPoolPropertyMenu.mm │ ├── ZetaPoolWatcher.h │ ├── ZetaPoolWatcher.mm │ ├── ZetaQueryDialog.h │ ├── ZetaQueryDialog.mm │ ├── ZetaSnapshotMenu.h │ ├── ZetaSnapshotMenu.mm │ ├── ZetaWatch.entitlements │ ├── ZetaWatchDelegate.h │ ├── ZetaWatchDelegate.mm │ └── main.m ├── ZetaWatch.xcodeproj/ │ ├── project.pbxproj │ └── project.xcworkspace/ │ └── contents.xcworkspacedata └── uninstall-helper.sh
SYMBOL INDEX (43 symbols across 10 files)
FILE: ZetaAuthorizationHelper/ZetaCPPUtils.hpp
function formatForHumans (line 18) | inline std::string formatForHumans(std::vector<T> const & things)
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationDispatcher.cpp
type ID (line 24) | namespace ID
type DiskArbitrationDispatcher::Impl (line 26) | struct DiskArbitrationDispatcher::Impl
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationDispatcher.hpp
type ID (line 20) | namespace ID
class DiskArbitrationHandler (line 22) | class DiskArbitrationHandler
class DiskArbitrationDispatcher (line 27) | class DiskArbitrationDispatcher
type Impl (line 50) | struct Impl
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationHandler.hpp
type ID (line 18) | namespace ID
class DiskInformation (line 20) | class DiskInformation
class DiskArbitrationHandler (line 22) | class DiskArbitrationHandler
method DiskArbitrationHandler (line 25) | explicit DiskArbitrationHandler() {}
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationUtils.cpp
type ID (line 19) | namespace ID
function to_string (line 53) | std::string to_string(CFStringRef str)
function to_string (line 68) | std::string to_string(CFURLRef url)
function to_string (line 76) | std::string to_string(CFDataRef data)
function to_string (line 87) | std::string to_string(CFUUIDRef uuid)
function to_string (line 95) | std::string to_string(CFTypeRef variant)
function interpret_as_string (line 111) | std::string interpret_as_string(CFDataRef data)
function stringFromDictionary (line 119) | std::string stringFromDictionary(CFDictionaryRef dict, CFStringRef key)
function numberFromDictionary (line 126) | int64_t numberFromDictionary(CFDictionaryRef dict, CFStringRef key)
function boolFromDictionary (line 137) | bool boolFromDictionary(CFDictionaryRef dict, CFStringRef key)
function stringFromIOObjectWithParents (line 146) | std::string stringFromIOObjectWithParents(io_object_t ioObject, CFStri...
function serialNumberFromIOObject (line 159) | std::string serialNumberFromIOObject(io_object_t ioObject)
function imagePathFromIOObject (line 175) | std::string imagePathFromIOObject(io_object_t ioObject)
function DiskInformation (line 195) | DiskInformation getDiskInformation(DADiskRef disk)
function isDevice (line 241) | bool isDevice(DiskInformation const & di)
function isWhole (line 246) | bool isWhole(DiskInformation const & di)
function partitionSuffix (line 251) | std::string partitionSuffix(DiskInformation const & di)
FILE: ZetaWatch/InvariantDisks/IDDiskArbitrationUtils.hpp
type ID (line 21) | namespace ID
type DiskInformation (line 23) | struct DiskInformation
FILE: ZetaWatch/ZetaCommanderBase.h
function interface (line 18) | interface ZetaCommanderBase : NSObject
function end (line 28) | end
FILE: ZetaWatch/ZetaFormatHelpers.hpp
type Prefix (line 17) | struct Prefix
function formatPrefixedValue (line 30) | std::string formatPrefixedValue(T size, Prefix const * prefix, size_t pr...
function formatInformationValue (line 46) | std::string formatInformationValue(T size)
function formatNormalValue (line 52) | std::string formatNormalValue(T size)
function formatBytes (line 58) | std::string formatBytes(T bytes)
function parseBytes (line 64) | bool parseBytes(char const * byteString, T & outBytes)
function formatRate (line 95) | inline std::string formatRate(uint64_t bytes, std::chrono::seconds const...
function T (line 100) | T toFormatable(T t)
function trim (line 110) | inline std::string trim(std::string const & s)
FILE: ZetaWatch/ZetaMainMenu.h
type ZetaMenuTags (line 26) | enum ZetaMenuTags
FILE: ZetaWatch/ZetaNotificationCenter.h
function interface (line 13) | interface ZetaNotification : NSObject
Condensed preview — 70 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (422K chars).
[
{
"path": ".gitignore",
"chars": 31,
"preview": "Archive\nDerivedData\nxcuserdata\n"
},
{
"path": ".gitmodules",
"chars": 147,
"preview": "[submodule \"ThirdParty/Sparkle\"]\n\tpath = ThirdParty/Sparkle\n\turl = ../Sparkle.git\n[submodule \"ZFSWrapper\"]\n\tpath = ZFSWr"
},
{
"path": "CommonAuthorization/CommonAuthorization.h",
"chars": 507,
"preview": "//\n// CommonAuthorization.h\n// ZetaWatch\n//\n// Created by cbreak on 18.01.01.\n// Copyright © 2018 the-color-black.ne"
},
{
"path": "CommonAuthorization/CommonAuthorization.m",
"chars": 9233,
"preview": "//\n// CommonAuthorization.m\n// ZetaWatch\n//\n// Created by cbreak on 18.01.01.\n// Copyright © 2018 the-color-black.ne"
},
{
"path": "LICENSE.md",
"chars": 1484,
"preview": "Copyright (c) 2014, Gerhard Röthlin\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or wit"
},
{
"path": "README.md",
"chars": 9099,
"preview": "ZetaWatch\n=========\n\n![ZetaWatch displaying pool status and filesystems][ZFSImage]\n\nZetaWatch is a small OS X program th"
},
{
"path": "ZetaAuthorizationHelper/Info.plist",
"chars": 916,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ZetaAuthorizationHelper/Launchd.plist",
"chars": 377,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ZetaAuthorizationHelper/ZetaAuthorizationHelper.h",
"chars": 279,
"preview": "//\n// ZetaAuthorizationHelper.h\n// ZetaAuthorizationHelper\n//\n// Created by cbreak on 18.01.01.\n// Copyright © 2018 "
},
{
"path": "ZetaAuthorizationHelper/ZetaAuthorizationHelper.mm",
"chars": 19295,
"preview": "//\n// ZetaAuthorizationHelper.m\n// ZetaAuthorizationHelper\n//\n// Created by cbreak on 18.01.01.\n// Copyright © 2018 "
},
{
"path": "ZetaAuthorizationHelper/ZetaAuthorizationHelperProtocol.h",
"chars": 2275,
"preview": "//\n// ZetaAuthorizationHelperProtocol.h\n// ZetaWatch\n//\n// Created by cbreak on 18.01.01.\n// Copyright © 2018 the-co"
},
{
"path": "ZetaAuthorizationHelper/ZetaCPPUtils.hpp",
"chars": 565,
"preview": "//\n// ZetaCPPUtils.hpp\n// ZetaWatch\n//\n// Created by cbreak on 19.07.28.\n// Copyright © 2019 the-color-black.net. Al"
},
{
"path": "ZetaAuthorizationHelper/main.m",
"chars": 393,
"preview": "//\n// main.m\n// ZetaAuthorizationHelper\n//\n// Created by cbreak on 18.01.01.\n// Copyright © 2018 the-color-black.net"
},
{
"path": "ZetaLoginItemHelper/Info.plist",
"chars": 1081,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ZetaLoginItemHelper/main.m",
"chars": 820,
"preview": "//\n// main.m\n// ZetaLoginItemHelper\n//\n// Created by cbreak on 19.11.02.\n// Copyright © 2019 the-color-black.net. Al"
},
{
"path": "ZetaWatch/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1300,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"16x16\",\n \"idiom\" : \"mac\",\n \"filename\" : \"Zetaicoon-16.png\",\n \"scal"
},
{
"path": "ZetaWatch/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "ZetaWatch/Assets.xcassets/Zeta.imageset/Contents.json",
"chars": 306,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"Zetaicoon.pdf\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "ZetaWatch/Base.lproj/MainMenu.xib",
"chars": 99100,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "ZetaWatch/Base.lproj/NewFS.xib",
"chars": 13023,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "ZetaWatch/Base.lproj/NewVol.xib",
"chars": 16119,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
},
{
"path": "ZetaWatch/Info.plist",
"chars": 2007,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ZetaWatch/InvariantDisks/IDDiskArbitrationDispatcher.cpp",
"chars": 3057,
"preview": "//\n// IDDiskArbitrationDispatcher.cpp\n// InvariantDisks\n//\n// Created by Gerhard Röthlin on 2014.04.27.\n// Copyright"
},
{
"path": "ZetaWatch/InvariantDisks/IDDiskArbitrationDispatcher.hpp",
"chars": 1242,
"preview": "//\n// IDDiskArbitrationDispatcher.hpp\n// InvariantDisks\n//\n// Created by Gerhard Röthlin on 2014.04.27.\n// Copyright"
},
{
"path": "ZetaWatch/InvariantDisks/IDDiskArbitrationHandler.hpp",
"chars": 915,
"preview": "//\n// IDDiskArbitrationHandler.hpp\n// InvariantDisks\n//\n// Created by Gerhard Röthlin on 2014.04.27.\n// Copyright (c"
},
{
"path": "ZetaWatch/InvariantDisks/IDDiskArbitrationUtils.cpp",
"chars": 9272,
"preview": "//\n// IDDiskArbitrationUtils.cpp\n// InvariantDisks\n//\n// Created by Gerhard Röthlin on 2014.04.27.\n// Copyright (c) "
},
{
"path": "ZetaWatch/InvariantDisks/IDDiskArbitrationUtils.hpp",
"chars": 1566,
"preview": "//\n// IDDiskArbitrationUtils.hpp\n// InvariantDisks\n//\n// Created by Gerhard Röthlin on 2014.04.27.\n// Copyright (c) "
},
{
"path": "ZetaWatch/PathValueTransformer.m",
"chars": 943,
"preview": "//\n// PathValueTransformer.m\n// ZetaWatch\n//\n// Created by cbreak on 19.11.08.\n// Copyright © 2019 the-color-black.n"
},
{
"path": "ZetaWatch/SizeTransformer.mm",
"chars": 1156,
"preview": "//\n// SizeTransformer.m\n// ZetaWatch\n//\n// Created by cbreak on 19.11.08.\n// Copyright © 2019 the-color-black.net. A"
},
{
"path": "ZetaWatch/ZetaAuthorization.h",
"chars": 2190,
"preview": "//\n// ZetaAuthoized.h\n// ZetaWatch\n//\n// Created by cbreak on 17.12.31.\n// Copyright © 2017 the-color-black.net. All"
},
{
"path": "ZetaWatch/ZetaAuthorization.mm",
"chars": 14552,
"preview": "//\n// ZetaAuthoized.m\n// ZetaWatch\n//\n// Created by cbreak on 17.12.31.\n// Copyright © 2017 the-color-black.net. All"
},
{
"path": "ZetaWatch/ZetaAutoImporter.h",
"chars": 420,
"preview": "//\n// ZetaAutoImporter.h\n// ZetaWatch\n//\n// Created by cbreak on 19.08.02.\n// Copyright © 2019 the-color-black.net. "
},
{
"path": "ZetaWatch/ZetaAutoImporter.mm",
"chars": 7668,
"preview": "//\n// ZetaIDWatcher.cpp\n// ZetaWatch\n//\n// Created by cbreak on 19.08.02.\n// Copyright © 2019 the-color-black.net. A"
},
{
"path": "ZetaWatch/ZetaBookmarkMenu.h",
"chars": 484,
"preview": "//\n// ZetaBookmarkMenu.h\n// ZetaWatch\n//\n// Created by cbreak on 19.12.14.\n// Copyright © 2019 the-color-black.net. "
},
{
"path": "ZetaWatch/ZetaBookmarkMenu.mm",
"chars": 1597,
"preview": "//\n// ZetaBookmarkMenu.m\n// ZetaWatch\n//\n// Created by cbreak on 19.12.14.\n// Copyright © 2019 the-color-black.net. "
},
{
"path": "ZetaWatch/ZetaCommanderBase.h",
"chars": 1652,
"preview": "//\n// ZetaCommanderBase.h\n// ZetaWatch\n//\n// Created by cbreak on 19.06.02.\n// Copyright © 2019 the-color-black.net."
},
{
"path": "ZetaWatch/ZetaCommanderBase.mm",
"chars": 1422,
"preview": "//\n// ZetaCommanderBase.mm\n// ZetaWatch\n//\n// Created by cbreak on 19.06.02.\n// Copyright © 2019 the-color-black.net"
},
{
"path": "ZetaWatch/ZetaConfirmDialog.h",
"chars": 649,
"preview": "//\n// ZetaConfirmDialog.h\n// ZetaWatch\n//\n// Created by cbreak on 19.10.13.\n// Copyright © 2019 the-color-black.net."
},
{
"path": "ZetaWatch/ZetaConfirmDialog.mm",
"chars": 1982,
"preview": "//\n// ZetaConfirmDialog.mm\n// ZetaWatch\n//\n// Created by cbreak on 19.10.13.\n// Copyright © 2019 the-color-black.net"
},
{
"path": "ZetaWatch/ZetaDictQueryDialog.h",
"chars": 634,
"preview": "//\n// ZetaDictQueryDialog.h\n// ZetaWatch\n//\n// Created by cbreak on 19.10.06.\n// Copyright © 2019 the-color-black.ne"
},
{
"path": "ZetaWatch/ZetaDictQueryDialog.mm",
"chars": 2067,
"preview": "//\n// ZetaNewFSDialog.mm\n// ZetaWatch\n//\n// Created by cbreak on 19.10.06.\n// Copyright © 2019 the-color-black.net. "
},
{
"path": "ZetaWatch/ZetaFileSystemPropertyMenu.h",
"chars": 439,
"preview": "//\n// ZetaFileSystemPropertyMenu.h\n// ZetaWatch\n//\n// Created by cbreak on 19.06.22.\n// Copyright © 2019 the-color-b"
},
{
"path": "ZetaWatch/ZetaFileSystemPropertyMenu.mm",
"chars": 807,
"preview": "//\n// ZetaFileSystemPropertyMenu.mm\n// ZetaWatch\n//\n// Created by cbreak on 19.06.22.\n// Copyright © 2019 the-color-"
},
{
"path": "ZetaWatch/ZetaFormatHelpers.cpp",
"chars": 786,
"preview": "//\n// ZetaFormatHelpers.cpp\n// ZetaWatch\n//\n// Created by cbreak on 19.06.22.\n// Copyright © 2019 the-color-black.ne"
},
{
"path": "ZetaWatch/ZetaFormatHelpers.hpp",
"chars": 2792,
"preview": "//\n// ZetaFormatHelpers.hpp\n// ZetaWatch\n//\n// Created by cbreak on 19.06.22.\n// Copyright © 2019 the-color-black.ne"
},
{
"path": "ZetaWatch/ZetaImportMenu.h",
"chars": 606,
"preview": "//\n// ZetaImportMenu.h\n// ZetaWatch\n//\n// Created by cbreak on 19.06.02.\n// Copyright © 2019 the-color-black.net. Al"
},
{
"path": "ZetaWatch/ZetaImportMenu.mm",
"chars": 4983,
"preview": "//\n// ZetaImportMenu.m\n// ZetaWatch\n//\n// Created by cbreak on 19.06.02.\n// Copyright © 2019 the-color-black.net. Al"
},
{
"path": "ZetaWatch/ZetaKeyLoader.h",
"chars": 1032,
"preview": "//\n// ZetaKeyLoader.h\n// ZetaWatch\n//\n// Created by cbreak on 19.06.16.\n// Copyright © 2019 the-color-black.net. All"
},
{
"path": "ZetaWatch/ZetaKeyLoader.mm",
"chars": 12275,
"preview": "//\n// ZetaKeyLoader.m\n// ZetaWatch\n//\n// Created by cbreak on 19.06.16.\n// Copyright © 2019 the-color-black.net. All"
},
{
"path": "ZetaWatch/ZetaMainMenu.h",
"chars": 2118,
"preview": "//\n// ZetaMainMenu.h\n// ZetaWatch\n//\n// Created by Gerhard Röthlin on 2015.12.20.\n// Copyright © 2015 the-color-blac"
},
{
"path": "ZetaWatch/ZetaMainMenu.mm",
"chars": 40250,
"preview": "//\n// ZetaMainMenu.mm\n// ZetaWatch\n//\n// Created by Gerhard Röthlin on 2015.12.20.\n// Copyright © 2015 the-color-bla"
},
{
"path": "ZetaWatch/ZetaNotificationCenter.h",
"chars": 792,
"preview": "//\n// ZetaNotificationCenter.h\n// ZetaWatch\n//\n// Created by cbreak on 19.08.25.\n// Copyright © 2019 the-color-black"
},
{
"path": "ZetaWatch/ZetaNotificationCenter.mm",
"chars": 2230,
"preview": "//\n// ZetaNotificationCenter.m\n// ZetaWatch\n//\n// Created by cbreak on 19.08.25.\n// Copyright © 2019 the-color-black"
},
{
"path": "ZetaWatch/ZetaPoolPropertyMenu.h",
"chars": 417,
"preview": "//\n// ZetaPoolPropertyMenu.h\n// ZetaWatch\n//\n// Created by cbreak on 19.06.22.\n// Copyright © 2019 the-color-black.n"
},
{
"path": "ZetaWatch/ZetaPoolPropertyMenu.mm",
"chars": 599,
"preview": "//\n// ZetaPoolPropertyMenu.mm\n// ZetaWatch\n//\n// Created by cbreak on 19.06.22.\n// Copyright © 2019 the-color-black."
},
{
"path": "ZetaWatch/ZetaPoolWatcher.h",
"chars": 923,
"preview": "//\n// ZetaPoolWatcher.h\n// ZetaWatch\n//\n// Created by Gerhard Röthlin on 2015.12.31.\n// Copyright © 2015 the-color-b"
},
{
"path": "ZetaWatch/ZetaPoolWatcher.mm",
"chars": 5086,
"preview": "//\n// ZetaPoolWatcher.mm\n// ZetaWatch\n//\n// Created by Gerhard Röthlin on 2015.12.31.\n// Copyright © 2015 the-color-"
},
{
"path": "ZetaWatch/ZetaQueryDialog.h",
"chars": 656,
"preview": "//\n// ZetaQueryDialog.h\n// ZetaWatch\n//\n// Created by cbreak on 19.10.06.\n// Copyright © 2019 the-color-black.net. A"
},
{
"path": "ZetaWatch/ZetaQueryDialog.mm",
"chars": 1979,
"preview": "//\n// ZetaQueryDialog.mm\n// ZetaWatch\n//\n// Created by cbreak on 19.10.06.\n// Copyright © 2019 the-color-black.net. "
},
{
"path": "ZetaWatch/ZetaSnapshotMenu.h",
"chars": 484,
"preview": "//\n// ZetaSnapshotMenu.h\n// ZetaWatch\n//\n// Created by cbreak on 19.10.05.\n// Copyright © 2019 the-color-black.net. "
},
{
"path": "ZetaWatch/ZetaSnapshotMenu.mm",
"chars": 2425,
"preview": "//\n// ZetaSnapshotMenu.m\n// ZetaWatch\n//\n// Created by cbreak on 19.10.05.\n// Copyright © 2019 the-color-black.net. "
},
{
"path": "ZetaWatch/ZetaWatch.entitlements",
"chars": 258,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ZetaWatch/ZetaWatchDelegate.h",
"chars": 728,
"preview": "//\n// ZetaWatchDelegate.h\n// ZetaWatch\n//\n// Created by Gerhard Röthlin on 2015.12.20.\n// Copyright © 2015 the-color"
},
{
"path": "ZetaWatch/ZetaWatchDelegate.mm",
"chars": 4744,
"preview": "//\n// ZetaWatchDelegate.mm\n// ZetaWatch\n//\n// Created by Gerhard Röthlin on 2015.12.20.\n// Copyright © 2015 the-colo"
},
{
"path": "ZetaWatch/main.m",
"chars": 252,
"preview": "//\n// main.m\n// ZetaWatch\n//\n// Created by Gerhard Röthlin on 2015.12.20.\n// Copyright © 2015 the-color-black.net. A"
},
{
"path": "ZetaWatch.xcodeproj/project.pbxproj",
"chars": 67031,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "ZetaWatch.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 154,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:ZetaWatch.xcode"
},
{
"path": "uninstall-helper.sh",
"chars": 255,
"preview": "#!/bin/sh\n\nlaunchctl unload /Library/LaunchDaemons/net.the-color-black.ZetaAuthorizationHelper.plist\nrm /Library/LaunchD"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the cbreak-black/ZetaWatch GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 70 files (377.9 KB), approximately 102.9k tokens, and a symbol index with 43 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.