Repo // Deprecating Zonble's FSEventStreamHelper.
This commit is contained in:
parent
70de63dd35
commit
f5bec584a5
1
AUTHORS
1
AUTHORS
|
@ -18,7 +18,6 @@ $ Contributors and volunteers of the upstream repo, having no responsibility in
|
|||
- McBopomofo for macOS 2.x architect.
|
||||
- Voltaire candidate window MK2 (massively modified as MK3 in vChewing by Shiki Suen).
|
||||
- Notifier window and Tooltip UI.
|
||||
- FSEventStreamHelper.
|
||||
- App-style installer (only preserved for developer purposes).
|
||||
- mgrPrefs (userdefaults manager).
|
||||
- apiUpdate.
|
||||
|
|
|
@ -82,10 +82,8 @@
|
|||
|
||||
## 應用授權
|
||||
|
||||
威注音專案僅用到小麥注音的下述程式組件(MIT License):
|
||||
威注音專案目前僅用到小麥注音的下述程式組件(MIT License):
|
||||
|
||||
- 狀態管理引擎 & NSStringUtils & FSEventStreamHelper (by Zonble Yang),基於狀態設計模式:
|
||||
- ctlInputMethod 輸入法主控制器內則採用策略設計模式來處理各種狀態。
|
||||
- 半衰記憶模組的 C++ 原版作者是 Mengjuei Hsieh,且由 Shiki Suen 用 Swift 與 C# 分別重寫、繼續開發。
|
||||
- 僅供研發人員調試方便而使用的 App 版安裝程式 (by Zonble Yang),不對公眾使用。
|
||||
- Voltaire MK2 選字窗、飄雲通知視窗 (by Zonble Yang),有大幅度修改。
|
||||
|
|
|
@ -82,10 +82,8 @@
|
|||
|
||||
## 应用授权
|
||||
|
||||
威注音专案仅用到小麦注音的下述程式组件(MIT License):
|
||||
威注音专案目前仅用到小麦注音的下述程式组件(MIT License):
|
||||
|
||||
- 状态管理引擎 & NSStringUtils & FSEventStreamHelper (by Zonble Yang),基于状态设计模式:
|
||||
- ctlInputMethod 输入法主控制器内则采用策略设计模式来处理各种状态。
|
||||
- 半衰记忆模组的 C++ 原版作者是 Mengjuei Hsieh,且由 Shiki Suen 用 Swift 与 C# 分别重写、继续开发。
|
||||
- 仅供研发人员调试方便而使用的 App 版安装程式 (by Zonble Yang),不对公众使用。
|
||||
- Voltaire MK2 选字窗、飘云通知视窗 (by Zonble Yang),有大幅度修改。
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// (c) 2018 Daniel Galasko
|
||||
// Ref: https://medium.com/over-engineering/monitoring-a-folder-for-changes-in-ios-dc3f8614f902
|
||||
|
||||
import Foundation
|
||||
|
||||
class FolderMonitor {
|
||||
// MARK: Properties
|
||||
|
||||
/// A file descriptor for the monitored directory.
|
||||
private var monitoredFolderFileDescriptor: CInt = -1
|
||||
/// A dispatch queue used for sending file changes in the directory.
|
||||
private let folderMonitorQueue = DispatchQueue(label: "FolderMonitorQueue", attributes: .concurrent)
|
||||
/// A dispatch source to monitor a file descriptor created from the directory.
|
||||
private var folderMonitorSource: DispatchSourceFileSystemObject?
|
||||
/// URL for the directory being monitored.
|
||||
let url: URL
|
||||
|
||||
var folderDidChange: (() -> Void)?
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
init(url: URL) {
|
||||
self.url = url
|
||||
}
|
||||
|
||||
// MARK: Monitoring
|
||||
|
||||
/// Listen for changes to the directory (if we are not already).
|
||||
func startMonitoring() {
|
||||
guard folderMonitorSource == nil, monitoredFolderFileDescriptor == -1 else {
|
||||
return
|
||||
}
|
||||
// Open the directory referenced by URL for monitoring only.
|
||||
monitoredFolderFileDescriptor = open(url.path, O_EVTONLY)
|
||||
// Define a dispatch source monitoring the directory for additions, deletions, and renamings.
|
||||
folderMonitorSource = DispatchSource.makeFileSystemObjectSource(
|
||||
fileDescriptor: monitoredFolderFileDescriptor, eventMask: .write, queue: folderMonitorQueue
|
||||
)
|
||||
// Define the block to call when a file change is detected.
|
||||
folderMonitorSource?.setEventHandler { [weak self] in
|
||||
self?.folderDidChange?()
|
||||
}
|
||||
// Define a cancel handler to ensure the directory is closed when the source is cancelled.
|
||||
folderMonitorSource?.setCancelHandler { [weak self] in
|
||||
guard let strongSelf = self else { return }
|
||||
close(strongSelf.monitoredFolderFileDescriptor)
|
||||
strongSelf.monitoredFolderFileDescriptor = -1
|
||||
strongSelf.folderMonitorSource = nil
|
||||
}
|
||||
// Start monitoring the directory via the source.
|
||||
folderMonitorSource?.resume()
|
||||
}
|
||||
|
||||
/// Stop listening for changes to the directory, if the source has been created.
|
||||
func stopMonitoring() {
|
||||
folderMonitorSource?.cancel()
|
||||
}
|
||||
}
|
|
@ -12,10 +12,8 @@ import Cocoa
|
|||
import InputMethodKit
|
||||
|
||||
@objc(AppDelegate)
|
||||
class AppDelegate: NSObject, NSApplicationDelegate,
|
||||
FSEventStreamHelperDelegate, NSUserNotificationCenterDelegate
|
||||
{
|
||||
func helper(_: FSEventStreamHelper, didReceive _: [FSEventStreamHelper.Event]) {
|
||||
class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {
|
||||
private func reloadOnFolderChangeHappens() {
|
||||
// 拖 100ms 再重載,畢竟有些有特殊需求的使用者可能會想使用巨型自訂語彙檔案。
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
|
||||
if mgrPrefs.shouldAutoReloadUserDataFiles {
|
||||
|
@ -30,9 +28,8 @@ class AppDelegate: NSObject, NSApplicationDelegate,
|
|||
private var ctlPrefWindowInstance: ctlPrefWindow?
|
||||
private var ctlAboutWindowInstance: ctlAboutWindow? // New About Window
|
||||
private var checkTask: URLSessionTask?
|
||||
public var fsStreamHelper = FSEventStreamHelper(
|
||||
path: mgrLangModel.dataFolderPath(isDefaultFolder: false),
|
||||
queue: DispatchQueue(label: "vChewing User Phrases")
|
||||
public lazy var folderMonitor = FolderMonitor(
|
||||
url: URL(fileURLWithPath: mgrLangModel.dataFolderPath(isDefaultFolder: false))
|
||||
)
|
||||
private var currentAlertType: String = ""
|
||||
|
||||
|
@ -59,8 +56,10 @@ class AppDelegate: NSObject, NSApplicationDelegate,
|
|||
IME.initLangModels(userOnly: false)
|
||||
}
|
||||
|
||||
fsStreamHelper.delegate = self
|
||||
_ = fsStreamHelper.start()
|
||||
folderMonitor.folderDidChange = { [weak self] in
|
||||
self?.reloadOnFolderChangeHappens()
|
||||
}
|
||||
folderMonitor.startMonitoring()
|
||||
|
||||
mgrPrefs.fixOddPreferences()
|
||||
mgrPrefs.setMissingDefaults()
|
||||
|
@ -71,8 +70,15 @@ class AppDelegate: NSObject, NSApplicationDelegate,
|
|||
}
|
||||
}
|
||||
|
||||
func updateStreamHelperPath() {
|
||||
fsStreamHelper.path = mgrPrefs.userDataFolderSpecified
|
||||
func updateDirectoryMonitorPath() {
|
||||
folderMonitor.stopMonitoring()
|
||||
folderMonitor = FolderMonitor(
|
||||
url: URL(fileURLWithPath: mgrLangModel.dataFolderPath(isDefaultFolder: false))
|
||||
)
|
||||
folderMonitor.folderDidChange = { [weak self] in
|
||||
self?.reloadOnFolderChangeHappens()
|
||||
}
|
||||
folderMonitor.startMonitoring()
|
||||
}
|
||||
|
||||
func showPreferences() {
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// All possible vChewing-specific modifications are of:
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// ====================
|
||||
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
|
||||
// ... with NTL restriction stating that:
|
||||
// No trademark license is granted to use the trade names, trademarks, service
|
||||
// marks, or product names of Contributor, except as required to fulfill notice
|
||||
// requirements defined in MIT License.
|
||||
|
||||
import Cocoa
|
||||
|
||||
public protocol FSEventStreamHelperDelegate: AnyObject {
|
||||
func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event])
|
||||
}
|
||||
|
||||
public class FSEventStreamHelper {
|
||||
public struct Event {
|
||||
var path: String
|
||||
var flags: FSEventStreamEventFlags
|
||||
var id: FSEventStreamEventId
|
||||
}
|
||||
|
||||
public var path: String
|
||||
public let dispatchQueue: DispatchQueue
|
||||
public weak var delegate: FSEventStreamHelperDelegate?
|
||||
|
||||
public init(path: String, queue: DispatchQueue) {
|
||||
self.path = path
|
||||
dispatchQueue = queue
|
||||
}
|
||||
|
||||
private var stream: FSEventStreamRef?
|
||||
|
||||
public func start() -> Bool {
|
||||
if stream != nil {
|
||||
return false
|
||||
}
|
||||
var context = FSEventStreamContext()
|
||||
context.info = Unmanaged.passUnretained(self).toOpaque()
|
||||
guard
|
||||
let stream = FSEventStreamCreate(
|
||||
nil,
|
||||
{
|
||||
_, clientCallBackInfo, eventCount, eventPaths, eventFlags, eventIds in
|
||||
let helper = Unmanaged<FSEventStreamHelper>.fromOpaque(clientCallBackInfo!)
|
||||
.takeUnretainedValue()
|
||||
let pathsBase = eventPaths.assumingMemoryBound(to: UnsafePointer<CChar>.self)
|
||||
let pathsPtr = UnsafeBufferPointer(start: pathsBase, count: eventCount)
|
||||
let flagsPtr = UnsafeBufferPointer(start: eventFlags, count: eventCount)
|
||||
let eventIDsPtr = UnsafeBufferPointer(start: eventIds, count: eventCount)
|
||||
let events = (0..<eventCount).map {
|
||||
FSEventStreamHelper.Event(
|
||||
path: String(cString: pathsPtr[$0]),
|
||||
flags: flagsPtr[$0],
|
||||
id: eventIDsPtr[$0]
|
||||
)
|
||||
}
|
||||
helper.delegate?.helper(helper, didReceive: events)
|
||||
},
|
||||
&context,
|
||||
[path] as CFArray,
|
||||
UInt64(kFSEventStreamEventIdSinceNow),
|
||||
1.0,
|
||||
FSEventStreamCreateFlags(kFSEventStreamCreateFlagNone)
|
||||
)
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
FSEventStreamSetDispatchQueue(stream, dispatchQueue)
|
||||
if !FSEventStreamStart(stream) {
|
||||
FSEventStreamInvalidate(stream)
|
||||
return false
|
||||
}
|
||||
self.stream = stream
|
||||
return true
|
||||
}
|
||||
|
||||
func stop() {
|
||||
guard let stream = stream else {
|
||||
return
|
||||
}
|
||||
FSEventStreamStop(stream)
|
||||
FSEventStreamInvalidate(stream)
|
||||
self.stream = nil
|
||||
}
|
||||
}
|
|
@ -459,11 +459,10 @@ enum mgrLangModel {
|
|||
return false
|
||||
}
|
||||
|
||||
// We use FSEventStream to monitor possible changes of the user phrase folder, hence the
|
||||
// lack of the needs of manually load data here unless FSEventStream is disabled by user.
|
||||
if !mgrPrefs.shouldAutoReloadUserDataFiles {
|
||||
loadUserPhrasesData()
|
||||
}
|
||||
// The new FolderMonitor module does NOT monitor cases that files are modified
|
||||
// by the current application itself, requiring additional manual loading process here.
|
||||
// if !mgrPrefs.shouldAutoReloadUserDataFiles {}
|
||||
loadUserPhrasesData()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -82,7 +82,7 @@ struct suiPrefPaneDictionary: View {
|
|||
tbxUserDataPathSpecified = mgrPrefs.userDataFolderSpecified
|
||||
BookmarkManager.shared.saveBookmark(for: url)
|
||||
IME.initLangModels(userOnly: true)
|
||||
(NSApplication.shared.delegate as! AppDelegate).updateStreamHelperPath()
|
||||
(NSApplication.shared.delegate as! AppDelegate).updateDirectoryMonitorPath()
|
||||
} else {
|
||||
clsSFX.beep()
|
||||
if !bolPreviousFolderValidity {
|
||||
|
|
|
@ -236,7 +236,7 @@ class ctlPrefWindow: NSWindowController {
|
|||
mgrPrefs.userDataFolderSpecified = newPath
|
||||
BookmarkManager.shared.saveBookmark(for: url)
|
||||
IME.initLangModels(userOnly: true)
|
||||
(NSApplication.shared.delegate as! AppDelegate).updateStreamHelperPath()
|
||||
(NSApplication.shared.delegate as! AppDelegate).updateDirectoryMonitorPath()
|
||||
} else {
|
||||
clsSFX.beep()
|
||||
if !bolPreviousFolderValidity {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
5B09307628B6FC3B0021F8C5 /* shortcuts.html in Resources */ = {isa = PBXBuildFile; fileRef = 5B09307828B6FC3B0021F8C5 /* shortcuts.html */; };
|
||||
5B0AF8B527B2C8290096FE54 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0AF8B427B2C8290096FE54 /* StringExtension.swift */; };
|
||||
5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */; };
|
||||
5B16B84C28C9A89000ABA692 /* FolderMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B16B84B28C9A89000ABA692 /* FolderMonitor.swift */; };
|
||||
5B175FFB28C5CDDC0078D1B4 /* IMKHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B175FFA28C5CDDC0078D1B4 /* IMKHelper.swift */; };
|
||||
5B20430728BEE30900BFC6FD /* BookmarkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B20430628BEE30900BFC6FD /* BookmarkManager.swift */; };
|
||||
5B21176C287539BB000443A9 /* ctlInputMethod_HandleStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B21176B287539BB000443A9 /* ctlInputMethod_HandleStates.swift */; };
|
||||
|
@ -34,7 +35,6 @@
|
|||
5B5E535227EF261400C6AA1E /* IME.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5E535127EF261400C6AA1E /* IME.swift */; };
|
||||
5B5F8AEB28C86AAD007C11F1 /* NSAttributedTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F8AEA28C86AAD007C11F1 /* NSAttributedTextView.swift */; };
|
||||
5B5F8AEE28C8826D007C11F1 /* ctlTooltip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F8AED28C8826D007C11F1 /* ctlTooltip.swift */; };
|
||||
5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */; };
|
||||
5B62A33627AE795800A19448 /* mgrPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33527AE795800A19448 /* mgrPrefs.swift */; };
|
||||
5B62A33D27AE7CC100A19448 /* ctlAboutWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */; };
|
||||
5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */; };
|
||||
|
@ -212,6 +212,7 @@
|
|||
5B0AF8B427B2C8290096FE54 /* StringExtension.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = StringExtension.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B0C5EDF27C7D9870078037C /* dataCompiler.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = dataCompiler.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = AppleKeyboardConverter.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B16B84B28C9A89000ABA692 /* FolderMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderMonitor.swift; sourceTree = "<group>"; };
|
||||
5B175FFA28C5CDDC0078D1B4 /* IMKHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMKHelper.swift; sourceTree = "<group>"; };
|
||||
5B18BA6F27C7BD8B0056EB19 /* LICENSE-CHS.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-CHS.txt"; sourceTree = "<group>"; };
|
||||
5B18BA7027C7BD8B0056EB19 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
|
||||
|
@ -249,7 +250,6 @@
|
|||
5B5E535127EF261400C6AA1E /* IME.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = IME.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B5F8AEA28C86AAD007C11F1 /* NSAttributedTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedTextView.swift; sourceTree = "<group>"; };
|
||||
5B5F8AED28C8826D007C11F1 /* ctlTooltip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlTooltip.swift; sourceTree = "<group>"; };
|
||||
5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = FSEventStreamHelper.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B62A33527AE795800A19448 /* mgrPrefs.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrPrefs.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B62A34027AE7CD900A19448 /* ctlCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
|
@ -415,6 +415,14 @@
|
|||
path = DataCompiler;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B16B84A28C9A88300ABA692 /* FolderMonitor */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B16B84B28C9A89000ABA692 /* FolderMonitor.swift */,
|
||||
);
|
||||
path = FolderMonitor;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B18BA7527C7BF6D0056EB19 /* MiscRootFiles */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -476,6 +484,7 @@
|
|||
5B62A30127AE732800A19448 /* 3rdParty */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B16B84A28C9A88300ABA692 /* FolderMonitor */,
|
||||
5B84579B2871AD2200C93B01 /* HotenkaChineseConverter */,
|
||||
5B949BD72816DC4400D87B5D /* LineReader */,
|
||||
5B5F8AEC28C86AB3007C11F1 /* NSAttributedTextView */,
|
||||
|
@ -518,14 +527,6 @@
|
|||
path = ControllerModules;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B62A32127AE755D00A19448 /* FileHandlers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */,
|
||||
);
|
||||
path = FileHandlers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B62A32227AE756300A19448 /* IMEModules */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -856,7 +857,6 @@
|
|||
D427F76B278CA1BA004A2160 /* AppDelegate.swift */,
|
||||
D47B92BF27972AC800458394 /* main.swift */,
|
||||
5B62A31F27AE74E900A19448 /* ControllerModules */,
|
||||
5B62A32127AE755D00A19448 /* FileHandlers */,
|
||||
5B62A32227AE756300A19448 /* IMEModules */,
|
||||
5B62A32427AE757300A19448 /* LangModelRelated */,
|
||||
5B62A32327AE756800A19448 /* LanguageParsers */,
|
||||
|
@ -1246,7 +1246,7 @@
|
|||
5B62A34A27AE7CD900A19448 /* NotifierController.swift in Sources */,
|
||||
5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */,
|
||||
5B54E743283A7D89001ECBDC /* lmCoreNS.swift in Sources */,
|
||||
5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */,
|
||||
5B16B84C28C9A89000ABA692 /* FolderMonitor.swift in Sources */,
|
||||
5B2170E2289FACAD00BE7304 /* 8_Unigram.swift in Sources */,
|
||||
5B21176C287539BB000443A9 /* ctlInputMethod_HandleStates.swift in Sources */,
|
||||
5B62A33627AE795800A19448 /* mgrPrefs.swift in Sources */,
|
||||
|
|
Loading…
Reference in New Issue