File tree panel now uses FSEvent API instead of kqueues.

This commit is contained in:
vspader 2008-02-18 03:27:59 +00:00
parent e2399c12ca
commit 9414c97c09
19 changed files with 530 additions and 1603 deletions

View file

@ -10,6 +10,7 @@
07E18DF30D62B38400BB0E11 /* NSArray+ShuffleUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */; }; 07E18DF30D62B38400BB0E11 /* NSArray+ShuffleUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */; };
170680630B950158006BA573 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 170680620B950158006BA573 /* Growl.framework */; }; 170680630B950158006BA573 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 170680620B950158006BA573 /* Growl.framework */; };
170680840B950164006BA573 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 170680620B950158006BA573 /* Growl.framework */; }; 170680840B950164006BA573 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 170680620B950158006BA573 /* Growl.framework */; };
171192BD0D691ED600FD76C5 /* PathWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 171192BC0D691ED600FD76C5 /* PathWatcher.m */; };
171B57DD0C091F2B00F6AFAF /* flac.icns in Resources */ = {isa = PBXBuildFile; fileRef = 171B57D90C091F2B00F6AFAF /* flac.icns */; }; 171B57DD0C091F2B00F6AFAF /* flac.icns in Resources */ = {isa = PBXBuildFile; fileRef = 171B57D90C091F2B00F6AFAF /* flac.icns */; };
171B57DE0C091F2B00F6AFAF /* m4a.icns in Resources */ = {isa = PBXBuildFile; fileRef = 171B57DA0C091F2B00F6AFAF /* m4a.icns */; }; 171B57DE0C091F2B00F6AFAF /* m4a.icns in Resources */ = {isa = PBXBuildFile; fileRef = 171B57DA0C091F2B00F6AFAF /* m4a.icns */; };
171B57DF0C091F2B00F6AFAF /* mp3.icns in Resources */ = {isa = PBXBuildFile; fileRef = 171B57DB0C091F2B00F6AFAF /* mp3.icns */; }; 171B57DF0C091F2B00F6AFAF /* mp3.icns in Resources */ = {isa = PBXBuildFile; fileRef = 171B57DB0C091F2B00F6AFAF /* mp3.icns */; };
@ -44,10 +45,6 @@
177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF870B8BC2A70000BC8C /* ImageTextCell.m */; }; 177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF870B8BC2A70000BC8C /* ImageTextCell.m */; };
177EBFAB0B8BC2A70000BC8C /* NDHotKeyControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF8D0B8BC2A70000BC8C /* NDHotKeyControl.m */; }; 177EBFAB0B8BC2A70000BC8C /* NDHotKeyControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF8D0B8BC2A70000BC8C /* NDHotKeyControl.m */; };
177EBFAD0B8BC2A70000BC8C /* NDHotKeyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF8F0B8BC2A70000BC8C /* NDHotKeyEvent.m */; }; 177EBFAD0B8BC2A70000BC8C /* NDHotKeyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF8F0B8BC2A70000BC8C /* NDHotKeyEvent.m */; };
177EBFAF0B8BC2A70000BC8C /* UKFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF920B8BC2A70000BC8C /* UKFileWatcher.m */; };
177EBFB10B8BC2A70000BC8C /* UKFNSubscribeFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF940B8BC2A70000BC8C /* UKFNSubscribeFileWatcher.m */; };
177EBFB40B8BC2A70000BC8C /* UKKQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF970B8BC2A70000BC8C /* UKKQueue.m */; };
177EBFB60B8BC2A70000BC8C /* UKMainThreadProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF990B8BC2A70000BC8C /* UKMainThreadProxy.m */; };
177EC01F0B8BC2CF0000BC8C /* ClickField.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0130B8BC2CF0000BC8C /* ClickField.m */; }; 177EC01F0B8BC2CF0000BC8C /* ClickField.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0130B8BC2CF0000BC8C /* ClickField.m */; };
177EC0210B8BC2CF0000BC8C /* DBLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0150B8BC2CF0000BC8C /* DBLog.m */; }; 177EC0210B8BC2CF0000BC8C /* DBLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0150B8BC2CF0000BC8C /* DBLog.m */; };
177EC0230B8BC2CF0000BC8C /* DragScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0170B8BC2CF0000BC8C /* DragScrollView.m */; }; 177EC0230B8BC2CF0000BC8C /* DragScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0170B8BC2CF0000BC8C /* DragScrollView.m */; };
@ -475,6 +472,8 @@
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
1705F1420B8BCB0C00C8B40D /* English */ = {isa = PBXFileReference; lastKnownFileType = folder; name = English; path = English.lproj/Help; sourceTree = "<group>"; }; 1705F1420B8BCB0C00C8B40D /* English */ = {isa = PBXFileReference; lastKnownFileType = folder; name = English; path = English.lproj/Help; sourceTree = "<group>"; };
170680620B950158006BA573 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = ThirdParty/Frameworks/Growl.framework; sourceTree = "<group>"; }; 170680620B950158006BA573 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = ThirdParty/Frameworks/Growl.framework; sourceTree = "<group>"; };
171192BB0D691ED600FD76C5 /* PathWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PathWatcher.h; sourceTree = "<group>"; };
171192BC0D691ED600FD76C5 /* PathWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PathWatcher.m; sourceTree = "<group>"; };
171B57D90C091F2B00F6AFAF /* flac.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = flac.icns; sourceTree = "<group>"; }; 171B57D90C091F2B00F6AFAF /* flac.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = flac.icns; sourceTree = "<group>"; };
171B57DA0C091F2B00F6AFAF /* m4a.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = m4a.icns; sourceTree = "<group>"; }; 171B57DA0C091F2B00F6AFAF /* m4a.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = m4a.icns; sourceTree = "<group>"; };
171B57DB0C091F2B00F6AFAF /* mp3.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = mp3.icns; sourceTree = "<group>"; }; 171B57DB0C091F2B00F6AFAF /* mp3.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = mp3.icns; sourceTree = "<group>"; };
@ -529,15 +528,6 @@
177EBF8D0B8BC2A70000BC8C /* NDHotKeyControl.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NDHotKeyControl.m; sourceTree = "<group>"; }; 177EBF8D0B8BC2A70000BC8C /* NDHotKeyControl.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NDHotKeyControl.m; sourceTree = "<group>"; };
177EBF8E0B8BC2A70000BC8C /* NDHotKeyEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NDHotKeyEvent.h; sourceTree = "<group>"; }; 177EBF8E0B8BC2A70000BC8C /* NDHotKeyEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NDHotKeyEvent.h; sourceTree = "<group>"; };
177EBF8F0B8BC2A70000BC8C /* NDHotKeyEvent.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NDHotKeyEvent.m; sourceTree = "<group>"; }; 177EBF8F0B8BC2A70000BC8C /* NDHotKeyEvent.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NDHotKeyEvent.m; sourceTree = "<group>"; };
177EBF910B8BC2A70000BC8C /* UKFileWatcher.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = UKFileWatcher.h; sourceTree = "<group>"; };
177EBF920B8BC2A70000BC8C /* UKFileWatcher.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = UKFileWatcher.m; sourceTree = "<group>"; };
177EBF930B8BC2A70000BC8C /* UKFNSubscribeFileWatcher.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = UKFNSubscribeFileWatcher.h; sourceTree = "<group>"; };
177EBF940B8BC2A70000BC8C /* UKFNSubscribeFileWatcher.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = UKFNSubscribeFileWatcher.m; sourceTree = "<group>"; };
177EBF950B8BC2A70000BC8C /* UKKQueue Readme.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "UKKQueue Readme.txt"; sourceTree = "<group>"; };
177EBF960B8BC2A70000BC8C /* UKKQueue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = UKKQueue.h; sourceTree = "<group>"; };
177EBF970B8BC2A70000BC8C /* UKKQueue.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = UKKQueue.m; sourceTree = "<group>"; };
177EBF980B8BC2A70000BC8C /* UKMainThreadProxy.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = UKMainThreadProxy.h; sourceTree = "<group>"; };
177EBF990B8BC2A70000BC8C /* UKMainThreadProxy.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = UKMainThreadProxy.m; sourceTree = "<group>"; };
177EC0120B8BC2CF0000BC8C /* ClickField.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ClickField.h; sourceTree = "<group>"; }; 177EC0120B8BC2CF0000BC8C /* ClickField.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ClickField.h; sourceTree = "<group>"; };
177EC0130B8BC2CF0000BC8C /* ClickField.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ClickField.m; sourceTree = "<group>"; }; 177EC0130B8BC2CF0000BC8C /* ClickField.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ClickField.m; sourceTree = "<group>"; };
177EC0140B8BC2CF0000BC8C /* DBLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DBLog.h; sourceTree = "<group>"; }; 177EC0140B8BC2CF0000BC8C /* DBLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DBLog.h; sourceTree = "<group>"; };
@ -755,6 +745,8 @@
17211A680D68B79700911CA9 /* FileNode.m */, 17211A680D68B79700911CA9 /* FileNode.m */,
17211A6F0D68B79700911CA9 /* SmartFolderNode.h */, 17211A6F0D68B79700911CA9 /* SmartFolderNode.h */,
17211A700D68B79700911CA9 /* SmartFolderNode.m */, 17211A700D68B79700911CA9 /* SmartFolderNode.m */,
171192BB0D691ED600FD76C5 /* PathWatcher.h */,
171192BC0D691ED600FD76C5 /* PathWatcher.m */,
); );
path = FileTreeWindow; path = FileTreeWindow;
sourceTree = "<group>"; sourceTree = "<group>";
@ -793,7 +785,6 @@
177EBF850B8BC2A70000BC8C /* ImageTextCell */, 177EBF850B8BC2A70000BC8C /* ImageTextCell */,
179790DD0C087AB7001D6996 /* OpenURLPanel */, 179790DD0C087AB7001D6996 /* OpenURLPanel */,
177EBF8B0B8BC2A70000BC8C /* NDHotKeys */, 177EBF8B0B8BC2A70000BC8C /* NDHotKeys */,
177EBF900B8BC2A70000BC8C /* UKKQueue */,
); );
path = ThirdParty; path = ThirdParty;
sourceTree = "<group>"; sourceTree = "<group>";
@ -827,22 +818,6 @@
path = NDHotKeys; path = NDHotKeys;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
177EBF900B8BC2A70000BC8C /* UKKQueue */ = {
isa = PBXGroup;
children = (
177EBF910B8BC2A70000BC8C /* UKFileWatcher.h */,
177EBF920B8BC2A70000BC8C /* UKFileWatcher.m */,
177EBF930B8BC2A70000BC8C /* UKFNSubscribeFileWatcher.h */,
177EBF940B8BC2A70000BC8C /* UKFNSubscribeFileWatcher.m */,
177EBF950B8BC2A70000BC8C /* UKKQueue Readme.txt */,
177EBF960B8BC2A70000BC8C /* UKKQueue.h */,
177EBF970B8BC2A70000BC8C /* UKKQueue.m */,
177EBF980B8BC2A70000BC8C /* UKMainThreadProxy.h */,
177EBF990B8BC2A70000BC8C /* UKMainThreadProxy.m */,
);
path = UKKQueue;
sourceTree = "<group>";
};
177EC0110B8BC2CF0000BC8C /* Utils */ = { 177EC0110B8BC2CF0000BC8C /* Utils */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1649,10 +1624,6 @@
177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */, 177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */,
177EBFAB0B8BC2A70000BC8C /* NDHotKeyControl.m in Sources */, 177EBFAB0B8BC2A70000BC8C /* NDHotKeyControl.m in Sources */,
177EBFAD0B8BC2A70000BC8C /* NDHotKeyEvent.m in Sources */, 177EBFAD0B8BC2A70000BC8C /* NDHotKeyEvent.m in Sources */,
177EBFAF0B8BC2A70000BC8C /* UKFileWatcher.m in Sources */,
177EBFB10B8BC2A70000BC8C /* UKFNSubscribeFileWatcher.m in Sources */,
177EBFB40B8BC2A70000BC8C /* UKKQueue.m in Sources */,
177EBFB60B8BC2A70000BC8C /* UKMainThreadProxy.m in Sources */,
177EC01F0B8BC2CF0000BC8C /* ClickField.m in Sources */, 177EC01F0B8BC2CF0000BC8C /* ClickField.m in Sources */,
177EC0210B8BC2CF0000BC8C /* DBLog.m in Sources */, 177EC0210B8BC2CF0000BC8C /* DBLog.m in Sources */,
177EC0230B8BC2CF0000BC8C /* DragScrollView.m in Sources */, 177EC0230B8BC2CF0000BC8C /* DragScrollView.m in Sources */,
@ -1694,6 +1665,7 @@
17211A790D68B79700911CA9 /* SmartFolderNode.m in Sources */, 17211A790D68B79700911CA9 /* SmartFolderNode.m in Sources */,
17E78CB10D68D46F005C5A59 /* StringToURLTransformer.m in Sources */, 17E78CB10D68D46F005C5A59 /* StringToURLTransformer.m in Sources */,
56AE86C10D6901BC00B0F89B /* FontSizetoLineHeightTransformer.m in Sources */, 56AE86C10D6901BC00B0F89B /* FontSizetoLineHeightTransformer.m in Sources */,
171192BD0D691ED600FD76C5 /* PathWatcher.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View file

@ -74,7 +74,7 @@
<int key="NSCellFlags2">0</int> <int key="NSCellFlags2">0</int>
<string key="NSContents" id="607347959"/> <string key="NSContents" id="607347959"/>
<object class="NSFont" key="NSSupport" id="26"> <object class="NSFont" key="NSSupport" id="26">
<string key="NSName" id="226158462">LucidaGrande</string> <string key="NSName" id="819564220">LucidaGrande</string>
<double key="NSSize">1.100000e+01</double> <double key="NSSize">1.100000e+01</double>
<int key="NSfFlags">3100</int> <int key="NSfFlags">3100</int>
</object> </object>
@ -84,7 +84,7 @@
</object> </object>
<object class="NSColor" key="NSTextColor"> <object class="NSColor" key="NSTextColor">
<int key="NSColorSpace">6</int> <int key="NSColorSpace">6</int>
<string key="NSCatalogName" id="684352132">System</string> <string key="NSCatalogName" id="903547761">System</string>
<string key="NSColorName">headerTextColor</string> <string key="NSColorName">headerTextColor</string>
<object class="NSColor" key="NSColor" id="1016173790"> <object class="NSColor" key="NSColor" id="1016173790">
<int key="NSColorSpace">3</int> <int key="NSColorSpace">3</int>
@ -97,14 +97,14 @@
<int key="NSCellFlags2">2048</int> <int key="NSCellFlags2">2048</int>
<string key="NSContents">Text Cell</string> <string key="NSContents">Text Cell</string>
<object class="NSFont" key="NSSupport"> <object class="NSFont" key="NSSupport">
<reference key="NSName" ref="226158462"/> <reference key="NSName" ref="819564220"/>
<double key="NSSize">1.300000e+01</double> <double key="NSSize">1.300000e+01</double>
<int key="NSfFlags">1044</int> <int key="NSfFlags">1044</int>
</object> </object>
<reference key="NSControlView" ref="846237243"/> <reference key="NSControlView" ref="846237243"/>
<object class="NSColor" key="NSBackgroundColor" id="518416176"> <object class="NSColor" key="NSBackgroundColor" id="518416176">
<int key="NSColorSpace">6</int> <int key="NSColorSpace">6</int>
<reference key="NSCatalogName" ref="684352132"/> <reference key="NSCatalogName" ref="903547761"/>
<string key="NSColorName">controlBackgroundColor</string> <string key="NSColorName">controlBackgroundColor</string>
<object class="NSColor" key="NSColor"> <object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int> <int key="NSColorSpace">3</int>
@ -113,7 +113,7 @@
</object> </object>
<object class="NSColor" key="NSTextColor"> <object class="NSColor" key="NSTextColor">
<int key="NSColorSpace">6</int> <int key="NSColorSpace">6</int>
<reference key="NSCatalogName" ref="684352132"/> <reference key="NSCatalogName" ref="903547761"/>
<string key="NSColorName">controlTextColor</string> <string key="NSColorName">controlTextColor</string>
<reference key="NSColor" ref="1016173790"/> <reference key="NSColor" ref="1016173790"/>
</object> </object>
@ -128,7 +128,7 @@
<reference key="NSBackgroundColor" ref="518416176"/> <reference key="NSBackgroundColor" ref="518416176"/>
<object class="NSColor" key="NSGridColor"> <object class="NSColor" key="NSGridColor">
<int key="NSColorSpace">6</int> <int key="NSColorSpace">6</int>
<reference key="NSCatalogName" ref="684352132"/> <reference key="NSCatalogName" ref="903547761"/>
<string key="NSColorName">gridColor</string> <string key="NSColorName">gridColor</string>
<object class="NSColor" key="NSColor"> <object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int> <int key="NSColorSpace">3</int>
@ -223,6 +223,9 @@
<object class="NSUserDefaultsController" id="419060898"> <object class="NSUserDefaultsController" id="419060898">
<bool key="NSSharedInstance">YES</bool> <bool key="NSSharedInstance">YES</bool>
</object> </object>
<object class="NSCustomObject" id="257353879">
<string key="NSClassName">PathWatcher</string>
</object>
</object> </object>
<object class="IBObjectContainer" key="IBDocument.Objects"> <object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords"> <object class="NSMutableArray" key="connectionRecords">
@ -245,7 +248,7 @@
</object> </object>
<object class="IBConnectionRecord"> <object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection"> <object class="IBOutletConnection" key="connection">
<string key="label">delegate</string> <string key="label" id="1005462213">delegate</string>
<reference key="source" ref="846237243"/> <reference key="source" ref="846237243"/>
<reference key="destination" ref="1001"/> <reference key="destination" ref="1001"/>
</object> </object>
@ -279,6 +282,22 @@
</object> </object>
<int key="connectionID">30</int> <int key="connectionID">30</int>
</object> </object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<reference key="label" ref="1005462213"/>
<reference key="source" ref="257353879"/>
<reference key="destination" ref="381152635"/>
</object>
<int key="connectionID">33</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label" id="353012604">watcher</string>
<reference key="source" ref="381152635"/>
<reference key="destination" ref="257353879"/>
</object>
<int key="connectionID">34</int>
</object>
</object> </object>
<object class="IBMutableOrderedSet" key="objectRecords"> <object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects"> <object class="NSArray" key="orderedObjects">
@ -398,6 +417,11 @@
<reference key="object" ref="419060898"/> <reference key="object" ref="419060898"/>
<reference key="parent" ref="1002"/> <reference key="parent" ref="1002"/>
</object> </object>
<object class="IBObjectRecord">
<int key="objectID">31</int>
<reference key="object" ref="257353879"/>
<reference key="parent" ref="1002"/>
</object>
</object> </object>
</object> </object>
<object class="NSMutableDictionary" key="flattenedProperties"> <object class="NSMutableDictionary" key="flattenedProperties">
@ -427,6 +451,7 @@
<string>20.ImportedFromIB2</string> <string>20.ImportedFromIB2</string>
<string>25.IBPluginDependency</string> <string>25.IBPluginDependency</string>
<string>26.IBPluginDependency</string> <string>26.IBPluginDependency</string>
<string>31.IBPluginDependency</string>
<string>9.IBPluginDependency</string> <string>9.IBPluginDependency</string>
<string>9.ImportedFromIB2</string> <string>9.ImportedFromIB2</string>
</object> </object>
@ -455,6 +480,7 @@
<reference ref="9"/> <reference ref="9"/>
<reference ref="34123527"/> <reference ref="34123527"/>
<reference ref="34123527"/> <reference ref="34123527"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="34123527"/> <reference ref="34123527"/>
<reference ref="9"/> <reference ref="9"/>
</object> </object>
@ -479,14 +505,14 @@
</object> </object>
</object> </object>
<nil key="sourceID"/> <nil key="sourceID"/>
<int key="maxID">30</int> <int key="maxID">34</int>
</object> </object>
<object class="IBClassDescriber" key="IBDocument.Classes"> <object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions"> <object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className" id="696656415">NSObject</string> <string key="className">PathWatcher</string>
<nil key="superclassName"/> <string key="superclassName" id="696656415">NSObject</string>
<object class="NSMutableDictionary" key="actions"> <object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool> <bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys"> <object class="NSArray" key="dict.sortedKeys">
@ -497,173 +523,12 @@
</object> </object>
</object> </object>
<object class="NSMutableDictionary" key="outlets"> <object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool> <reference key="NS.key.0" ref="1005462213"/>
<object class="NSArray" key="dict.sortedKeys"> <string key="NS.object.0">id</string>
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object> </object>
<object class="IBClassDescriptionSource" key="sourceIdentifier"> <object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey" id="985237313">IBProjectSource</string> <string key="majorKey" id="599007926">IBProjectSource</string>
<string key="minorKey">ThirdParty/UKKQueue/UKKQueue.h</string> <string key="minorKey">FileTreeWindow/PathWatcher.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/>
<string key="minorKey">ThirdParty/UKKQueue/UKMainThreadProxy.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/>
<string key="minorKey">ThirdParty/UKKQueue/UKFileWatcher.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/>
<string key="minorKey">ThirdParty/AppleRemote/AppleRemote.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/>
<string key="minorKey">ThirdParty/NDHotKeys/NDHotKeyEvent.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/>
<string key="minorKey">ThirdParty/GCWindowMenu/GCOneShotEffectTimer.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">FileTreeWindowController</string>
<string key="superclassName">NSWindowController</string>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/>
<string key="minorKey">FileTreeWindow/FileTreeWindowController.h</string>
</object> </object>
</object> </object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
@ -688,10 +553,36 @@
</object> </object>
</object> </object>
<object class="IBClassDescriptionSource" key="sourceIdentifier"> <object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/> <reference key="majorKey" ref="599007926"/>
<string key="minorKey">FileTreeWindow/FileIconCell.h</string> <string key="minorKey">FileTreeWindow/FileIconCell.h</string>
</object> </object>
</object> </object>
<object class="IBPartialClassDescription">
<string key="className">FileTreeWindowController</string>
<string key="superclassName">NSWindowController</string>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="599007926"/>
<string key="minorKey">FileTreeWindow/FileTreeWindowController.h</string>
</object>
</object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className">FileTreeDataSource</string> <string key="className">FileTreeDataSource</string>
<reference key="superclassName" ref="696656415"/> <reference key="superclassName" ref="696656415"/>
@ -705,11 +596,20 @@
</object> </object>
</object> </object>
<object class="NSMutableDictionary" key="outlets"> <object class="NSMutableDictionary" key="outlets">
<string key="NS.key.0">outlineView</string> <bool key="EncodedWithXMLCoder">YES</bool>
<string key="NS.object.0">NSOutlineView</string> <object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>outlineView</string>
<reference ref="353012604"/>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSOutlineView</string>
<string>PathWatcher</string>
</object>
</object> </object>
<object class="IBClassDescriptionSource" key="sourceIdentifier"> <object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/> <reference key="majorKey" ref="599007926"/>
<string key="minorKey">FileTreeWindow/FileTreeDataSource.h</string> <string key="minorKey">FileTreeWindow/FileTreeDataSource.h</string>
</object> </object>
</object> </object>
@ -739,6 +639,162 @@
<reference key="minorKey" ref="607347959"/> <reference key="minorKey" ref="607347959"/>
</object> </object>
</object> </object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="599007926"/>
<string key="minorKey">ThirdParty/UKKQueue/UKFileWatcher.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="599007926"/>
<string key="minorKey">ThirdParty/UKKQueue/UKKQueue.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="599007926"/>
<string key="minorKey">ThirdParty/UKKQueue/UKMainThreadProxy.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="599007926"/>
<string key="minorKey">ThirdParty/GCWindowMenu/GCOneShotEffectTimer.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="599007926"/>
<string key="minorKey">ThirdParty/AppleRemote/AppleRemote.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<reference key="className" ref="696656415"/>
<nil key="superclassName"/>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="599007926"/>
<string key="minorKey">ThirdParty/NDHotKeys/NDHotKeyEvent.h</string>
</object>
</object>
<object class="IBPartialClassDescription"> <object class="IBPartialClassDescription">
<string key="className">ImageTextCell</string> <string key="className">ImageTextCell</string>
<string key="superclassName">NSTextFieldCell</string> <string key="superclassName">NSTextFieldCell</string>
@ -761,7 +817,7 @@
</object> </object>
</object> </object>
<object class="IBClassDescriptionSource" key="sourceIdentifier"> <object class="IBClassDescriptionSource" key="sourceIdentifier">
<reference key="majorKey" ref="985237313"/> <reference key="majorKey" ref="599007926"/>
<string key="minorKey">ThirdParty/ImageTextCell/ImageTextCell.h</string> <string key="minorKey">ThirdParty/ImageTextCell/ImageTextCell.h</string>
</object> </object>
</object> </object>
@ -772,123 +828,127 @@
<int key="IBDocument.defaultPropertyAccessControl">3</int> <int key="IBDocument.defaultPropertyAccessControl">3</int>
<object class="NSMutableData" key="IBDocument.RunnableNib"> <object class="NSMutableData" key="IBDocument.RunnableNib">
<bytes key="NS.bytes">YnBsaXN0MDDUAAEAAgADAAQABQAGAAkAClgkdmVyc2lvblQkdG9wWSRhcmNoaXZlclgkb2JqZWN0cxIA <bytes key="NS.bytes">YnBsaXN0MDDUAAEAAgADAAQABQAGAAkAClgkdmVyc2lvblQkdG9wWSRhcmNoaXZlclgkb2JqZWN0cxIA
AYag0QAHAAhdSUIub2JqZWN0ZGF0YYABXxAPTlNLZXllZEFyY2hpdmVyrxCWAAsADAAxADUANgA8AD0A AYag0QAHAAhdSUIub2JqZWN0ZGF0YYABXxAPTlNLZXllZEFyY2hpdmVyrxCfAAsADAAxADUANgA8AD0A
QgBYAFkAWgBbAAsAaQBuAIIAiACXAJsAvwDAAMYAxwDMANAA4gDuAO8A9wD4APsBAAEDAQsBDAENARAB QgBYAFkAWgBbAAsAaQBuAIIAiACXAJsAvwDAAMYAxwDMANAA4gDuAO8A9wD4APsBAAEDAQsBDAENARAB
FgEjARMBJAElASoBLwEwATMBOAE5ATwBPwFDAUgBSQFMAU0AvwFRAVQBYAFhAWIBZQFvAL8BcAFzAX4B FgEjARMBJAElASoBLwEwATMBOAE5ATwBPwFDAUgBSQFMAU0AvwFRAVQBYAFhAWIBZQFvAL8BcAFzAX4B
gwGEAYUBiQGKAZUBmAGbAZ4ACwGfAaEBogGlAa0BtQG2AboBvwHCAcMBxAHJAcoBzwHQAdwB4AHkAeUB gwGEAYUBiQGKAZUBmAGbAZ4ACwGfAaEBogGlAa8BtwG6AbsBvgG/AcABxAHJAcoBzwHQAdUB2gHbAeAB
5gHnAe4B7wHwAfMB9gIGAgkCCgIMAhwCLQI+Aj8CQAJBAkICQwJEAkUCRgJHAkgCSQJKAksCTwJTAmkC 4QHtAfEB9QH2AfcB+AH/AgACAQIEAgcCGAIbAhwCHgIvAkECUwJUAlUCVgJXAlgCWQJaAlsCXAJdAl4C
fwKAAoECggKDAoQChQKGAocCiAKJAooCiwKMAo0CjgBWAo8AuwKQApMClgKZVSRudWxs3xASAA0ADgAP XwJgAmECZQJpAoICmwKcAp0CngKfAqACoQKiAqMCpAKlAqYCpwKoAFYCqQKqALsCqwKsAq0CrgKvArIC
ABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAt tQK4VSRudWxs3xASAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAk
AC4ALwAwVk5TUm9vdFYkY2xhc3NdTlNPYmplY3RzS2V5c18QD05TQ2xhc3Nlc1ZhbHVlc18QGU5TQWNj ACUAJgAnACgAKQAqACsALAAtAC4ALwAwVk5TUm9vdFYkY2xhc3NdTlNPYmplY3RzS2V5c18QD05TQ2xh
ZXNzaWJpbGl0eU9pZHNWYWx1ZXNdTlNDb25uZWN0aW9uc1tOU05hbWVzS2V5c1tOU0ZyYW1ld29ya11O c3Nlc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eU9pZHNWYWx1ZXNdTlNDb25uZWN0aW9uc1tOU05hbWVz
U0NsYXNzZXNLZXlzWk5TT2lkc0tleXNdTlNOYW1lc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eUNvbm5l S2V5c1tOU0ZyYW1ld29ya11OU0NsYXNzZXNLZXlzWk5TT2lkc0tleXNdTlNOYW1lc1ZhbHVlc18QGU5T
Y3RvcnNdTlNGb250TWFuYWdlcl8QEE5TVmlzaWJsZVdpbmRvd3NfEA9OU09iamVjdHNWYWx1ZXNfEBdO QWNjZXNzaWJpbGl0eUNvbm5lY3RvcnNdTlNGb250TWFuYWdlcl8QEE5TVmlzaWJsZVdpbmRvd3NfEA9O
U0FjY2Vzc2liaWxpdHlPaWRzS2V5c1lOU05leHRPaWRcTlNPaWRzVmFsdWVzgAKAlYBngHyAlIBQgGyA U09iamVjdHNWYWx1ZXNfEBdOU0FjY2Vzc2liaWxpdHlPaWRzS2V5c1lOU05leHRPaWRcTlNPaWRzVmFs
BYB7gH2AbYCSgACABoBrgJMQIIB+0gAOADIAMwA0W05TQ2xhc3NOYW1lgASAA18QGEZpbGVUcmVlV2lu dWVzgAKAnoBsgIKAnYBQgHGABYCBgIOAcoCbgACABoBwgJwQJICE0gAOADIAMwA0W05TQ2xhc3NOYW1l
ZG93Q29udHJvbGxlctIANwA4ADkAOlgkY2xhc3Nlc1okY2xhc3NuYW1logA6ADteTlNDdXN0b21PYmpl gASAA18QGEZpbGVUcmVlV2luZG93Q29udHJvbGxlctIANwA4ADkAOlgkY2xhc3Nlc1okY2xhc3NuYW1l
Y3RYTlNPYmplY3RfEBBJQkNvY29hRnJhbWV3b3Jr0gAOAD4APwBAWk5TLm9iamVjdHOARaEAQYAH2wBD ogA6ADteTlNDdXN0b21PYmplY3RYTlNPYmplY3RfEBBJQkNvY29hRnJhbWV3b3Jr0gAOAD4APwBAWk5T
AA4ARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABQAFIAUwBUAFUAVgArXE5TV2luZG93Vmlld1xOU1Nj Lm9iamVjdHOARaEAQYAH2wBDAA4ARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABQAFIAUwBUAFUAVgAr
cmVlblJlY3RfEBNOU0ZyYW1lQXV0b3NhdmVOYW1lXU5TV2luZG93VGl0bGVZTlNXVEZsYWdzXU5TV2lu XE5TV2luZG93Vmlld1xOU1NjcmVlblJlY3RfEBNOU0ZyYW1lQXV0b3NhdmVOYW1lXU5TV2luZG93VGl0
ZG93Q2xhc3NcTlNXaW5kb3dSZWN0XxAPTlNXaW5kb3dCYWNraW5nXxARTlNXaW5kb3dTdHlsZU1hc2tb bGVZTlNXVEZsYWdzXU5TV2luZG93Q2xhc3NcTlNXaW5kb3dSZWN0XxAPTlNXaW5kb3dCYWNraW5nXxAR
TlNWaWV3Q2xhc3OAC4BPgE6ACYAJE/////+kAAQAgAqACBACEB+AAF8QGHt7MTk2LCAxMTJ9LCB7MzA2 TlNXaW5kb3dTdHlsZU1hc2tbTlNWaWV3Q2xhc3OAC4BPgE6ACYAJE/////+kAAQAgAqACBACEB+AAF8Q
LCAzOTh9fVlGaWxlIFRyZWVXTlNQYW5lbNcAXAAOAF0AXgBfAGAAYQBiAGMAZABlAGYAYgBoXxAPTlNO GHt7MTk2LCAxMTJ9LCB7MzA2LCAzOTh9fVlGaWxlIFRyZWVXTlNQYW5lbNcAXAAOAF0AXgBfAGAAYQBi
ZXh0UmVzcG9uZGVyWk5TU3Vidmlld3NYTlN2RmxhZ3NbTlNGcmFtZVNpemVYTlNXaW5kb3dbTlNTdXBl AGMAZABlAGYAYgBoXxAPTlNOZXh0UmVzcG9uZGVyWk5TU3Vidmlld3NYTlN2RmxhZ3NbTlNGcmFtZVNp
cnZpZXeADIBNgA0RAQCAS4AMgEzSAA4APgBqAGuAMaIAbABtgA6AQd0AXABvAA4AcABdAHEAXgBfAGAA emVYTlNXaW5kb3dbTlNTdXBlcnZpZXeADIBNgA0RAQCAS4AMgEzSAA4APgBqAGuAMaIAbABtgA6AQd0A
YQByAHMAdABNAHYAdwB4AHkAegB7AHwAYgBNAH8AgACAW05TSFNjcm9sbGVyWE5Tc0ZsYWdzXE5TU2Ny XABvAA4AcABdAHEAXgBfAGAAYQByAHMAdABNAHYAdwB4AHkAegB7AHwAYgBNAH8AgACAW05TSFNjcm9s
b2xsQW10c1tOU1ZTY3JvbGxlcl1OU05leHRLZXlWaWV3XU5TQ29udGVudFZpZXeAC4A9gEARAjCAD08Q bGVyWE5Tc0ZsYWdzXE5TU2Nyb2xsQW10c1tOU1ZTY3JvbGxlcl1OU05leHRLZXlWaWV3XU5TQ29udGVu
EEEgAABBIAAAQZgAAEGYAAARARKAP4AMgAuAOYAQgBDSAA4APgBqAISAMaMAgAB/AHaAEIA5gD3bAFwA dFZpZXeAC4A9gEARAjCAD08QEEEgAABBIAAAQZgAAEGYAAARARKAP4AMgAuAOYAQgBDSAA4APgBqAISA
DgCJAF0AXgBfAIoAYACLAGEAcwBsAI0AjgCPAJAAkQCSAGIAlABsAJJZTlNjdkZsYWdzWU5TRG9jVmll MaMAgAB/AHaAEIA5gD3bAFwADgCJAF0AXgBfAIoAYACLAGEAcwBsAI0AjgCPAJAAkQCSAGIAlABsAJJZ
d1lOU0JHQ29sb3KADoA4EASAEREJAIA3gBKADIAqgA6AEtIADgA+AGoAmYAxoQCSgBLfEBUAXACcAA4A TlNjdkZsYWdzWU5TRG9jVmlld1lOU0JHQ29sb3KADoA4EASAEREJAIA3gBKADIAqgA6AEtIADgA+AGoA
nQCeAJ8AoAChAKIAowBeAF8ApAClAGAApgCnAKgAYQCpAKoAgACsAK0ArgCUALAAsQCyAI4AswC0ALUA mYAxoQCSgBLfEBUAXACcAA4AnQCeAJ8AoAChAKIAowBeAF8ApAClAGAApgCnAKgAYQCpAKoAgACsAK0A
sAC3AGIAsAC6ALsAgAC9AL5fEB9OU0RyYWdnaW5nU291cmNlTWFza0Zvck5vbkxvY2FsWU5TVHZGbGFn rgCUALAAsQCyAI4AswC0ALUAsAC3AGIAsAC6ALsAgAC9AL5fEB9OU0RyYWdnaW5nU291cmNlTWFza0Zv
c18QEU5TQmFja2dyb3VuZENvbG9yXxASTlNBbGxvd3NUeXBlU2VsZWN0XE5TQ29ybmVyVmlld18QF05T ck5vbkxvY2FsWU5TVHZGbGFnc18QEU5TQmFja2dyb3VuZENvbG9yXxASTlNBbGxvd3NUeXBlU2VsZWN0
SW50ZXJjZWxsU3BhY2luZ1dpZHRoXxAZTlNDb2x1bW5BdXRvcmVzaXppbmdTdHlsZV8QGE5TSW50ZXJj XE5TQ29ybmVyVmlld18QF05TSW50ZXJjZWxsU3BhY2luZ1dpZHRoXxAZTlNDb2x1bW5BdXRvcmVzaXpp
ZWxsU3BhY2luZ0hlaWdodFlOU0VuYWJsZWReTlNBdXRvc2F2ZU5hbWVfECVOU091dGxpbmVWaWV3QXV0 bmdTdHlsZV8QGE5TSW50ZXJjZWxsU3BhY2luZ0hlaWdodFlOU0VuYWJsZWReTlNBdXRvc2F2ZU5hbWVf
b3NhdmVFeHBhbmRlZEl0ZW1zS2V5W05TR3JpZENvbG9yXxAcTlNEcmFnZ2luZ1NvdXJjZU1hc2tGb3JM ECVOU091dGxpbmVWaWV3QXV0b3NhdmVFeHBhbmRlZEl0ZW1zS2V5W05TR3JpZENvbG9yXxAcTlNEcmFn
b2NhbF5OU1RhYmxlQ29sdW1uc1tOU1Jvd0hlaWdodIAQEACANhJawAAAgCoJgBQjQAgAAAAAAAAjQAAA Z2luZ1NvdXJjZU1hc2tGb3JMb2NhbF5OU1RhYmxlQ29sdW1uc1tOU1Jvd0hlaWdodIAQEACANhJawAAA
AAAAAAAREQCAEwmANYAMCYAyEA+AEIAXI0AxAAAAAAAAWnszMDYsIDM3N33UAFwADgDBAF4AKwDDAMQA gCoJgBQjQAgAAAAAAAAjQAAAAAAAAAAREQCAEwmANYAMCYAyEA+AEIAXI0AxAAAAAAAAWnszMDYsIDM3
xVdOU0ZyYW1lgACAFoAVE/////+AAAEAXxAUe3stMjYsIDB9LCB7MTYsIDE3fX3SADcAOADIAMmkAMkA N33UAFwADgDBAF4AKwDDAMQAxVdOU0ZyYW1lgACAFoAVE/////+AAAEAXxAUe3stMjYsIDB9LCB7MTYs
ygDLADtdX05TQ29ybmVyVmlld1ZOU1ZpZXdbTlNSZXNwb25kZXLSAA4APgBqAM6AMaEAz4AY2QDRAA4A IDE3fX3SADcAOADIAMmkAMkAygDLADtdX05TQ29ybmVyVmlld1ZOU1ZpZXdbTlNSZXNwb25kZXLSAA4A
0gDTANQA1QDWANcA2ACwANoA2wDcAN0A3gDfAOAAkl5OU0lzUmVzaXplYWJsZVxOU0hlYWRlckNlbGxX PgBqAM6AMaEAz4AY2QDRAA4A0gDTANQA1QDWANcA2ACwANoA2wDcAN0A3gDfAOAAkl5OU0lzUmVzaXpl
TlNXaWR0aFpOU0RhdGFDZWxsXk5TUmVzaXppbmdNYXNrWk5TTWluV2lkdGhaTlNNYXhXaWR0aFtOU1Rh YWJsZVxOU0hlYWRlckNlbGxXTlNXaWR0aFpOU0RhdGFDZWxsXk5TUmVzaXppbmdNYXNrWk5TTWluV2lk
YmxlVmlldwmAMIAZI0By8AAAAAAAgCUQAyNAMAAAAAAAACNAj0AAAAAAAIAS1wDjAA4AngDkAOUA5gDn dGhaTlNNYXhXaWR0aFtOU1RhYmxlVmlldwmAMIAZI0By8AAAAAAAgCUQAyNAMAAAAAAAACNAj0AAAAAA
AOgA6QDqAOsA7ACsAO1bTlNDZWxsRmxhZ3NaTlNDb250ZW50c1lOU1N1cHBvcnRcTlNDZWxsRmxhZ3My AIAS1wDjAA4AngDkAOUA5gDnAOgA6QDqAOsA7ACsAO1bTlNDZWxsRmxhZ3NaTlNDb250ZW50c1lOU1N1
W05TVGV4dENvbG9yEgSB/gCAJIAegBqAG4AgUNQADgDwAPEA8gDzAPQA9QD2Vk5TU2l6ZVZOU05hbWVY cHBvcnRcTlNDZWxsRmxhZ3MyW05TVGV4dENvbG9yEgSB/gCAJIAegBqAG4AgUNQADgDwAPEA8gDzAPQA
TlNmRmxhZ3OAHSNAJgAAAAAAAIAcEQwcXEx1Y2lkYUdyYW5kZdIANwA4APkA+qIA+gA7Vk5TRm9udNMA 9QD2Vk5TU2l6ZVZOU05hbWVYTlNmRmxhZ3OAHSNAJgAAAAAAAIAcEQwcXEx1Y2lkYUdyYW5kZdIANwA4
DgD8AP0A/gDeAP9cTlNDb2xvclNwYWNlV05TV2hpdGWAH0swLjMzMzMzMjk5ANIANwA4AQEBAqIBAgA7 APkA+qIA+gA7Vk5TRm9udNMADgD8AP0A/gDeAP9cTlNDb2xvclNwYWNlV05TV2hpdGWAH0swLjMzMzMz
V05TQ29sb3LVAA4BAgD8AQQBBQD+AQcBCAEJAQpbTlNDb2xvck5hbWVdTlNDYXRhbG9nTmFtZYAfgCMQ Mjk5ANIANwA4AQEBAqIBAgA7V05TQ29sb3LVAA4BAgD8AQQBBQD+AQcBCAEJAQpbTlNDb2xvck5hbWVd
BoAigCFWU3lzdGVtXxAPaGVhZGVyVGV4dENvbG9y0wAOAPwA/QD+AN4BD4AfQjAA0gA3ADgBEQESpQES TlNDYXRhbG9nTmFtZYAfgCMQBoAigCFWU3lzdGVtXxAPaGVhZGVyVGV4dENvbG9y0wAOAPwA/QD+AN4B
ARMBFAEVADtfEBFOU1RhYmxlSGVhZGVyQ2VsbF8QD05TVGV4dEZpZWxkQ2VsbFxOU0FjdGlvbkNlbGxW D4AfQjAA0gA3ADgBEQESpQESARMBFAEVADtfEBFOU1RhYmxlSGVhZGVyQ2VsbF8QD05TVGV4dEZpZWxk
TlNDZWxs2gDjAA4BFwCeAOQA5QEYAOYAMgDnARkBGgEbAJQBHQEeAJIBIAEhASJfEBNOU09yaWdpbmFs Q2VsbFxOU0FjdGlvbkNlbGxWTlNDZWxs2gDjAA4BFwCeAOQA5QEYAOYAMgDnARkBGgEbAJQBHQEeAJIB
Q2xhc3NOYW1lXU5TQ29udHJvbFZpZXcSFCH+QYAvgCeAKoAogCmAEhEIAIAmgC1cRmlsZUljb25DZWxs IAEhASJfEBNOU09yaWdpbmFsQ2xhc3NOYW1lXU5TQ29udHJvbFZpZXcSFCH+QYAvgCeAKoAogCmAEhEI
WVRleHQgQ2VsbNQADgDwAPEA8gDzAScA9QEpgB0jQCoAAAAAAACAHBEEFNUADgECAPwBBAEFAP4BLAEI AIAmgC1cRmlsZUljb25DZWxsWVRleHQgQ2VsbNQADgDwAPEA8gDzAScA9QEpgB0jQCoAAAAAAACAHBEE
AS0BCoAfgCyAK4AhXxAWY29udHJvbEJhY2tncm91bmRDb2xvctMADgD8AP0A/gDeATKAH0swLjY2NjY2 FNUADgECAPwBBAEFAP4BLAEIAS0BCoAfgCyAK4AhXxAWY29udHJvbEJhY2tncm91bmRDb2xvctMADgD8
NjY5ANUADgECAPwBBAEFAP4BBwEIATYBCoAfgCOALoAhXxAQY29udHJvbFRleHRDb2xvctIANwA4AToB AP0A/gDeATKAH0swLjY2NjY2NjY5ANUADgECAPwBBAEFAP4BBwEIATYBCoAfgCOALoAhXxAQY29udHJv
O6IBOwA7Xk5TQ2xhc3NTd2FwcGVy0gA3ADgBPQE+ogE+ADtdTlNUYWJsZUNvbHVtbtIANwA4AUABQaMB bFRleHRDb2xvctIANwA4AToBO6IBOwA7Xk5TQ2xhc3NTd2FwcGVy0gA3ADgBPQE+ogE+ADtdTlNUYWJs
QQFCADteTlNNdXRhYmxlQXJyYXlXTlNBcnJhedUADgECAPwBBAEFAP4BRQEIAUYBCoAfgDSAM4AhWWdy ZUNvbHVtbtIANwA4AUABQaMBQQFCADteTlNNdXRhYmxlQXJyYXlXTlNBcnJhedUADgECAPwBBAEFAP4B
aWRDb2xvctMADgD8AP0A/gDeAUuAH0QwLjUAWEZpbGVUcmVl0gA3ADgBTgFPpgFPANgBUADKAMsAO11O RQEIAUYBCoAfgDSAM4AhWWdyaWRDb2xvctMADgD8AP0A/gDeAUuAH0QwLjUAWEZpbGVUcmVl0gA3ADgB
U091dGxpbmVWaWV3WU5TQ29udHJvbNIANwA4AVIBU6QBUwDKAMsAO1pOU0NsaXBWaWV32QBcAVUADgDB TgFPpgFPANgBUADKAMsAO11OU091dGxpbmVWaWV3WU5TQ29udHJvbNIANwA4AVIBU6QBUwDKAMsAO1pO
AF4AYAFWAGEBVwBsAGwBWgFbAMUAYgFdAGwBX1hOU1RhcmdldFhOU0FjdGlvbllOU1BlcmNlbnSADoAO U0NsaXBWaWV32QBcAVUADgDBAF4AYAFWAGEBVwBsAGwBWgFbAMUAYgFdAGwBX1hOU1RhcmdldFhOU0Fj
gDyAOoAMgDuADiM/7+pioAAAAF8QFXt7MjYxLCAwfSwgezE1LCAzNjN9fVxfZG9TY3JvbGxlcjrSADcA dGlvbllOU1BlcmNlbnSADoAOgDyAOoAMgDuADiM/7+pioAAAAF8QFXt7MjYxLCAwfSwgezE1LCAzNjN9
OAFjAWSlAWQBUADKAMsAO1pOU1Njcm9sbGVy2gBcAVUADgDBAHAAXgBgAVYAYQFXAGwAbAFaAWkBagDF fVxfZG9TY3JvbGxlcjrSADcAOAFjAWSlAWQBUADKAMsAO1pOU1Njcm9sbGVy2gBcAVUADgDBAHAAXgBg
AGIBXQBsAW6ADoAOgDyAPhABgAyAO4AOIz/v4m0gAAAAXxAVe3swLCAzNjN9LCB7MjYxLCAxNX190gA3 AVYAYQFXAGwAbAFaAWkBagDFAGIBXQBsAW6ADoAOgDyAPhABgAyAO4AOIz/v4m0gAAAAXxAVe3swLCAz
ADgBcQFypAFyAMoAywA7XE5TU2Nyb2xsVmlld9kAXAAOAMEBFQF0AF4ApABgAGEATQF2AXcBeAF5AXoA NjN9LCB7MjYxLCAxNX190gA3ADgBcQFypAFyAMoAywA7XE5TU2Nyb2xsVmlld9kAXAAOAMEBFQF0AF4A
sABiAE1bTlNEcmFnVHlwZXOAC4BKgEaAR4BCEQEOCYAMgAvSAA4APgA/AYCARaIBgQGCgEOARF8QGUFw pABgAGEATQF2AXcBeAF5AXoAsABiAE1bTlNEcmFnVHlwZXOAC4BKgEaAR4BCEQEOCYAMgAvSAA4APgA/
cGxlIFVSTCBwYXN0ZWJvYXJkIHR5cGVfEBVOU0ZpbGVuYW1lc1Bib2FyZFR5cGXSADcAOAGGAYejAYcB AYCARaIBgQGCgEOARF8QGUFwcGxlIFVSTCBwYXN0ZWJvYXJkIHR5cGVfEBVOU0ZpbGVuYW1lc1Bib2Fy
iAA7XE5TTXV0YWJsZVNldFVOU1NldF8QFnt7LTEsIDM3N30sIHszMDcsIDIyfX3YAYsA4wAOAOUBGADm ZFR5cGXSADcAOAGGAYejAYcBiAA7XE5TTXV0YWJsZVNldFVOU1NldF8QFnt7LTEsIDM3N30sIHszMDcs
AYwBjQBVAY4BjwDsAG0BkgGTAG1bTlNQYXRoU3R5bGVfEBROU1BhdGhDb21wb25lbnRDZWxsc1pOU0Rl IDIyfX3YAYsA4wAOAOUBGADmAYwBjQBVAY4BjwDsAG0BkgGTAG1bTlNQYXRoU3R5bGVfEBROU1BhdGhD
bGVnYXRlEhQh/gGASYAbgEESAAKAAIBIgEHSAA4APgBqAZeAMaDSADcAOAGZAZqkAZoBFAEVADtaTlNQ b21wb25lbnRDZWxsc1pOU0RlbGVnYXRlEhQh/gGASYAbgEESAAKAAIBIgEHSAA4APgBqAZeAMaDSADcA
YXRoQ2VsbNIANwA4AZwBnaUBnQFQAMoAywA7XU5TUGF0aENvbnRyb2xaezMwNiwgMzk4fdIANwA4AaAA OAGZAZqkAZoBFAEVADtaTlNQYXRoQ2VsbNIANwA4AZwBnaUBnQFQAMoAywA7XU5TUGF0aENvbnRyb2xa
yqMAygDLADtfEBZ7ezAsIDB9LCB7MTY4MCwgMTAyOH190gA3ADgBowGkogGkADtfEBBOU1dpbmRvd1Rl ezMwNiwgMzk4fdIANwA4AaAAyqMAygDLADtfEBZ7ezAsIDB9LCB7MTY4MCwgMTAyOH190gA3ADgBowGk
bXBsYXRl0gAOAD4AagGngDGlAagBqQGqAasBrIBRgFSAWIBagFzUAA4BrgGvAbABsQAfAJIBtF1OU0Rl ogGkADtfEBBOU1dpbmRvd1RlbXBsYXRl0gAOAD4AagGngDGnAagBqQGqAasBrAGtAa6AUYBYgFqAXIBd
c3RpbmF0aW9uWE5TU291cmNlV05TTGFiZWyAU4ACgBKAUlhkZWxlZ2F0ZdIANwA4AbcBuKMBuAG5ADtf gF+AYdQADgGwAbEBsgGzAbQBtQG2XU5TRGVzdGluYXRpb25YTlNTb3VyY2VXTlNMYWJlbIBXgFSAUoBW
EBROU05pYk91dGxldENvbm5lY3Rvcl5OU05pYkNvbm5lY3RvctQADgGuAa8BsAGxAJIBvQG+gFOAEoBV 0gAOADIAMwG5gASAU1tQYXRoV2F0Y2hlctIADgAyADMBvYAEgFVfEBJGaWxlVHJlZURhdGFTb3VyY2VY
gFfSAA4AMgAzAcGABIBWXxASRmlsZVRyZWVEYXRhU291cmNlW291dGxpbmVWaWV31AAOAa4BrwGwAbEA ZGVsZWdhdGXSADcAOAHBAcKjAcIBwwA7XxAUTlNOaWJPdXRsZXRDb25uZWN0b3JeTlNOaWJDb25uZWN0
QQAfAciAU4AHgAKAWVZ3aW5kb3fUAA4BrgGvAbABsQG9AJIBzoBTgFWAEoBbWmRhdGFTb3VyY2XYAA4B b3LUAA4BsAGxAbIBswG1AbQByIBXgFKAVIBZV3dhdGNoZXLUAA4BsAGxAbIBswBBAB8BzoBXgAeAAoBb
rgHRAdIBrwGwAdMB1AHVAdYB1wHYAG0B2gHbAFVZTlNLZXlQYXRoWU5TQmluZGluZ1lOU09wdGlvbnNf VndpbmRvd9QADgGwAbEBsgGzAB8AkgG2gFeAAoASgFbUAA4BsAGxAbIBswG0AJIB2YBXgFSAEoBeWmRh
EBxOU05pYkJpbmRpbmdDb25uZWN0b3JWZXJzaW9ugGaAXYBhgGCAQYBfgGLSAA4B3QHeALBfEBBOU1No dGFTb3VyY2XUAA4BsAGxAbIBswCSAbQB34BXgBKAVIBgW291dGxpbmVWaWV32AAOAbAB4gHjAbEBsgHk
YXJlZEluc3RhbmNlgF4J0gA3ADgB4QHiowHiAeMAO18QGE5TVXNlckRlZmF1bHRzQ29udHJvbGxlclxO AeUB5gHnAegB6QBtAesB7ABVWU5TS2V5UGF0aFlOU0JpbmRpbmdZTlNPcHRpb25zXxAcTlNOaWJCaW5k
U0NvbnRyb2xsZXJfEB12YWx1ZTogdmFsdWVzLmZpbGVUcmVlUm9vdFVSTFV2YWx1ZV8QFnZhbHVlcy5m aW5nQ29ubmVjdG9yVmVyc2lvboBrgGKAZoBlgEGAZIBn0gAOAe4B7wCwXxAQTlNTaGFyZWRJbnN0YW5j
aWxlVHJlZVJvb3RVUkzTAA4B6AA+AekB6gHsV05TLmtleXOAZaEB64BjoQHtgGRfEBZOU1ZhbHVlVHJh ZYBjCdIANwA4AfIB86MB8wH0ADtfEBhOU1VzZXJEZWZhdWx0c0NvbnRyb2xsZXJcTlNDb250cm9sbGVy
bnNmb3JtZXJOYW1lXxAWU3RyaW5nVG9VUkxUcmFuc2Zvcm1lctIANwA4AfEB8qIB8gA7XE5TRGljdGlv XxAddmFsdWU6IHZhbHVlcy5maWxlVHJlZVJvb3RVUkxVdmFsdWVfEBZ2YWx1ZXMuZmlsZVRyZWVSb290
bmFyedIANwA4AfQB9aMB9QG5ADtfEBVOU05pYkJpbmRpbmdDb25uZWN0b3LSAA4APgH3AfiAaq0BvQB2 VVJM0wAOAfkAPgH6AfsB/VdOUy5rZXlzgGqhAfyAaKEB/oBpXxAWTlNWYWx1ZVRyYW5zZm9ybWVyTmFt
AE0AbADdAG0AfwF4AgEAzwHWAEEAkoBVgD2AC4AOgCWAQYA5gEeAaIAYgF2AB4AS0gAOADIAMwIIgASA ZV8QFlN0cmluZ1RvVVJMVHJhbnNmb3JtZXLSADcAOAICAgOiAgMAO1xOU0RpY3Rpb25hcnnSADcAOAIF
aV1OU0FwcGxpY2F0aW9u0gA3ADgCCwFCogFCADvSAA4APgH3Ag6Aaq0AHwBsAEEATQDPAE0AbABtAB8A AgajAgYBwwA7XxAVTlNOaWJCaW5kaW5nQ29ubmVjdG9y0gAOAD4CCAIJgG+uAN0ATQIMAH8AbQBBAHYB
kgAfAB8AbIACgA6AB4ALgBiAC4AOgEGAAoASgAKAAoAO0gAOAD4B9wIegGquAb0AdgBNAGwA3QHWAG0B tADPAXgB5wG1AJIAbIAlgAuAbYA5gEGAB4A9gFSAGIBHgGKAUoASgA7SAA4AMgAzAhqABIBuXU5TQXBw
eAIBAH8AzwBBAB8AkoBVgD2AC4AOgCWAXYBBgEeAaIA5gBiAB4ACgBLSAA4APgH3Ai+Aaq4BwQIxAjIC bGljYXRpb27SADcAOAIdAUKiAUIAO9IADgA+AggCIIBvrgDPAEEAHwBsAE0AHwBsAB8AkgBtAB8AHwBs
MwI0AjUCNgI3AjgCOQI6AjsCPAI9gFaAboBvgHCAcYBygHOAdIB1gHaAd4B4gHmAel8QE0hvcml6b250 AE2AGIAHgAKADoALgAKADoACgBKAQYACgAKADoAL0gAOAD4CCAIxgG+vEA8A3QBNAgwAbQAfAH8AQQB2
YWwgU2Nyb2xsZXJcQ29udGVudCBWaWV3W1Njcm9sbCBWaWV3XxAaRmlsZSBJY29uIENlbGwgKFRleHQg AbQBeAHnAM8BtQCSAGyAJYALgG2AQYACgDmAB4A9gFSAR4BigBiAUoASgA7SAA4APgIIAkOAb68QDwJE
Q2VsbClfEB9TaGFyZWQgVXNlciBEZWZhdWx0cyBDb250cm9sbGVyXxAaUG9wIFVwIFBhdGggQ29udHJv AkUCRgJHAkgCSQJKAksBvQJNAk4CTwJQAlECUoBzgHSAdYB2gHeAeIB5gHqAVYB7gHyAfYB+gH+AgF8Q
bCBXaWRnZXRZUGF0aCBDZWxsW0FwcGxpY2F0aW9uXxARVmVydGljYWwgU2Nyb2xsZXJcVGFibGUgQ29s GkZpbGUgSWNvbiBDZWxsIChUZXh0IENlbGwpXENvbnRlbnQgVmlld1tBcHBsaWNhdGlvbl8QGlBvcCBV
dW1uXxARUGFuZWwgKEZpbGUgVHJlZSlcRmlsZSdzIE93bmVyXE91dGxpbmUgVmlld9IADgA+AfcCTYBq cCBQYXRoIENvbnRyb2wgV2lkZ2V0XEZpbGUncyBPd25lcl8QEVZlcnRpY2FsIFNjcm9sbGVyXxARUGFu
oQDdgCXSAA4APgH3AlGAaqEBIYAm0gAOAD4B9wJVgGqvEBMBvQB2AasATQGqAGwA3QGoAG0AfwIBAM8B ZWwgKEZpbGUgVHJlZSlfEBNIb3Jpem9udGFsIFNjcm9sbGVyWVBhdGggQ2VsbF8QH1NoYXJlZCBVc2Vy
eAHWAakAQQAfAawAkoBVgD2AWoALgFiADoAlgFGAQYA5gGiAGIBHgF2AVIAHgAKAXIAS0gAOAD4B9wJr IERlZmF1bHRzIENvbnRyb2xsZXJcVGFibGUgQ29sdW1uXFBhdGggV2F0Y2hlclxPdXRsaW5lIFZpZXdb
gGqvEBMCbAJtAm4CbwJwAnECcgJzAnQCdQJ2AncCeAJ5AnoCewJ8An0CfoB/gICAgYCCgIOAhICFgIaA U2Nyb2xsIFZpZXfSAA4APgIIAmOAb6EA3YAl0gAOAD4CCAJngG+hASGAJtIADgA+AggCa4BvrxAWAakA
h4CIgImAioCLgIyAjYCOgI+AkICREAkQERAWEAsQGBAOEBQQFxAZEBAT//////////0QExAaEBsQFRAK 3QGtAE0AbQIMAB8AfwBBAHYBtADPAXgB5wG1AagBqgCSAGwBrgGrAayAWIAlgF+AC4BBgG2AAoA5gAeA
EB7SAA4APgBqApKAMaDSAA4APgH3ApWAaqDSAA4APgH3ApiAaqDSADcAOAKaApuiApsAO15OU0lCT2Jq PYBUgBiAR4BigFKAUYBagBKADoBhgFyAXdIADgA+AggChIBvrxAWAoUChgKHAogCiQKKAosCjAKNAo4C
ZWN0RGF0YQAIABkAIgAnADEAOgA/AEQAUgBUAGYBlQGbAeYB7QH0AgICFAIwAj4CSgJWAmQCbwJ9ApkC jwKQApECkgKTApQClQKWApcCmAKZApqAhYCGgIeAiICJgIqAi4CMgI2AjoCPgJCAkYCSgJOAlICVgJaA
pwK6AswC5gLwAv0C/wMBAwMDBQMHAwkDCwMNAw8DEQMTAxUDFwMZAxsDHQMfAyEDKgM2AzgDOgNVA14D l4CYgJmAmhAiEBQQFRALEBkT//////////0QIxAQEAoQERAJEBMQGhAbECEQGBAOEB4QFxAW0gAOAD4A
ZwNyA3cDhgOPA6IDqwO2A7gDuwO9A+oD9wQEBBoEKAQyBEAETQRfBHMEfwSBBIMEhQSHBIkEkgSUBJYE agKxgDGg0gAOAD4CCAK0gG+g0gAOAD4CCAK3gG+g0gA3ADgCuQK6ogK6ADteTlNJQk9iamVjdERhdGEA
mASaBJwEtwTBBMkE5gT4BQMFDAUYBSEFLQUvBTEFMwU2BTgFOgU8BUUFRwVMBU4FUAWFBZEFmgWnBbMF CAAZACIAJwAxADoAPwBEAFIAVABmAacBrQH4Af8CBgIUAiYCQgJQAlwCaAJ2AoECjwKrArkCzALeAvgD
wQXPBdEF0wXVBdgF2gXtBfAF8gX0BfYF+AX6BfwGBQYHBg4GEAYSBhQGQQZLBlUGXwZhBmMGZQZnBmoG AgMPAxEDEwMVAxcDGQMbAx0DHwMhAyMDJQMnAykDKwMtAy8DMQMzAzwDSANKA0wDZwNwA3kDhAOJA5gD
bAZuBnAGcgZ0BnYGfwaBBoQGhgbdBv8HCQcdBzIHPwdZB3UHkAeaB6kH0QfdB/wICwgXCBkIGwgdCCII oQO0A70DyAPKA80DzwP8BAkEFgQsBDoERARSBF8EcQSFBJEEkwSVBJcEmQSbBKQEpgSoBKoErASuBMkE
JAglCCcIMAg5CDwIPgg/CEEIQwhECEYISAhKCEwIVQhgCHEIeQh7CH0IfwiICJ8IqAixCL8IxgjSCNsI 0wTbBPgFCgUVBR4FKgUzBT8FQQVDBUUFSAVKBUwFTgVXBVkFXgVgBWIFlwWjBawFuQXFBdMF4QXjBeUF
3QjgCOIJBwkWCSMJKwk2CUUJUAlbCWcJaAlqCWwJdQl3CXkJggmLCY0Jqgm2CcEJywnYCeQJ6QnrCe0J 5wXqBewF/wYCBgQGBgYIBgoGDAYOBhcGGQYgBiIGJAYmBlMGXQZnBnEGcwZ1BncGeQZ8Bn4GgAaCBoQG
7wnxCfMJ9AoFCgwKEwocCh4KJwopCiwKOQpCCkcKTgpbCmgKcApyCn4KhwqMCpQKqQq1CsMKxQrHCskK hgaIBpEGkwaWBpgG7wcRBxsHLwdEB1EHaweHB6IHrAe7B+MH7wgOCB0IKQgrCC0ILwg0CDYINwg5CEII
ywrNCtQK5grzCvUK+AsBCwwLIAsyCz8LRgtvC4ULkwuYC5oLnAueC6ALogukC6cLqQurC7gLwgvTC9UL SwhOCFAIUQhTCFUIVghYCFoIXAheCGcIcgiDCIsIjQiPCJEImgixCLoIwwjRCNgI5AjtCO8I8gj0CRkJ
3gvgC+ML+Av6C/wL/gwADBkMJgwoDDQMSQxLDE0MTwxRDGQMbQxyDIEMigyPDJ0MpgytDLwMxAzZDNsM KAk1CT0JSAlXCWIJbQl5CXoJfAl+CYcJiQmLCZQJnQmfCbwJyAnTCd0J6gn2CfsJ/Qn/CgEKAwoFCgYK
3QzfDOEM6wz4DPoM/w0IDRENHg0sDTYNPw1IDVMNeA2BDYoNlA2WDZgNmg2cDZ4NoA2iDasNww3QDdkN FwoeCiUKLgowCjkKOwo+CksKVApZCmAKbQp6CoIKhAqQCpkKngqmCrsKxwrVCtcK2QrbCt0K3wrmCvgL
5A3vDhgOGg4cDh4OIA4iDiQOJg4oDjEOSQ5SDlsOaA6NDpkOmw6dDp8OoQ6jDqYOpw6pDqsOtA62DrsO BQsHCwoLEwseCzILRAtRC1gLgQuXC6ULqgusC64LsAuyC7QLtgu5C7sLvQvKC9QL5QvnC/AL8gv1DAoM
vQ6/DtsO8w78DwMPEA8WDy8PUA9cD3MPfg+DD4UPhw+JD44PkA+SD5sPnQ+eD6cPsA+7D8QPzw/dD+gP DAwODBAMEgwrDDgMOgxGDFsMXQxfDGEMYwx2DH8MhAyTDJwMoQyvDLgMvwzODNYM6wztDO8M8QzzDP0N
8Q/4EBEQGhAfEDIQOxA9EEgQShBMEE4QUBBSEGMQcRB6EIIQhBCGEIgQihCTEJwQoxC6EMkQ2hDcEN4Q Cg0MDRENGg0jDTANPg1IDVENWg1lDYoNkw2cDaYNqA2qDawNrg2wDbINtA29DdUN4g3rDfYOAQ4qDiwO
4BDiEOsQ7RDvEQQREBEhESMRJREnESkRMBFBEUMRRRFHEUkRVBF1EX8RiRGTEbIRtBG2EbgRuhG8Eb4R Lg4wDjIONA42DjgOOg5DDlsOZA5tDnoOnw6rDq0Orw6xDrMOtQ64DrkOuw69DsYOyA7NDs8O0Q7tDwUP
wBHJEdwR3hHfEegR7xIKEhcSNxI9ElYSYxJrEm0ScBJyEnUSdxKQEqkSshK3EsQSzRLUEuwS9RL3ExIT Dg8VDyIPKA9BD2IPbg+FD5APlQ+XD5kPmw+gD6IPpA+tD68PsA+5D8IPzQ/WD+EP7w/6EAMQChAjECwQ
FBMWExgTGhMcEx4TIBMiEyQTJhMoEyoTLBM1EzcTORNHE1ATVRNeE2ATexN9E38TgRODE4UThxOJE4sT MRBEEE0QTxBeEGAQYhBkEGYQaBBqEGwQfRCLEJQQnBCeEKAQohCkEK0QrxCxEL0QxhDIEMoQ3xDoEPEQ
jROPE5ETkxOVE54ToBO9E78TwRPDE8UTxxPJE8sTzRPPE9ET0xPVE9cT2RPiE+QUARQDFAUUBxQJFAsU +BEPER4RLxExETMRNRE3ET8RUBFSEVQRVhFYEV8RcBFyEXQRdhF4EYkRixGNEY8RkRGcEa0RrxGxEbMR
DRQPFBEUExQVFBcUGRQbFB0UMxRAFEwUaRSLFKgUshS+FNIU3xTzFQAVDRUWFRgVGxUdFSYVKBUrFS0V tRHBEeIR7BH2EgASHxIhEiMSJRInEikSKxItEjYSSRJLEkwSVRJcEncShBKkEqoSwxLQEtgS2hLdEt8S
NhU4FWEVYxVlFWcVaRVrFW0VbxVxFXMVdRV3FXkVexV9FX8VgRWDFYUVhxWQFZIVuxW9Fb8VwRXDFcUV 4hLkEv0TFhMfEyQTMRM6E0ETWRNiE2QTgRODE4UThxOJE4sTjROPE5ETkxOVE5cTmRObE50TphOoE6oT
xxXJFcsVzRXPFdEV0xXVFdcV2RXbFd0V3xXhFeMV5RXnFekV6xXtFe8V8RXzFfUV/hYAFgIWBBYGFggW uBPBE8YTzxPRE+4T8BPyE/QT9hP4E/oT/BP+FAAUAhQEFAYUCBQKFBMUFRQ2FDgUOhQ8FD4UQBRCFEQU
ChYTFhUWFhYfFiEWIhYrFi0WLhY3FjwAAAAAAAACAgAAAAAAAAKcAAAAAAAAAAAAAAAAAAAWSw</bytes> RhRIFEoUTBROFFAUUhRUFF0UXxSAFIIUhBSGFIgUihSMFI4UkBSSFJQUlhSYFJoUnBSeFLsUyBTUFPEU
/hUSFSYVPBVGFWgVdRWCFY8VmxWkFaYVqRWrFbQVthW5FbsVxBXGFfUV9xX5FfsV/RX/FgEWAxYFFgcW
CRYLFg0WDxYRFhMWFRYXFhkWGxYdFh8WIRYqFiwWWxZdFl8WYRZjFmUWZxZpFmsWbRZvFnEWcxZ1FncW
eRZ7Fn0WfxaBFoMWhRaHFokWixaNFo8WkRaaFpwWnhagFqIWpBamFqgWqhasFq4WsBayFrQWtha/FsEW
whbLFs0WzhbXFtkW2hbjFugAAAAAAAACAgAAAAAAAAK7AAAAAAAAAAAAAAAAAAAW9w</bytes>
</object> </object>
</data> </data>
</archive> </archive>

View file

@ -27,15 +27,4 @@
} }
} }
//Disable watching for us, it doesn't matter.
- (void)startWatching
{
}
- (void)stopWatching
{
}
- (void)updatePathNotification:(NSNotification *)notification
{
}
@end @end

View file

@ -15,15 +15,4 @@
return YES; return YES;
} }
//Disable watching for us, it doesn't matter.
- (void)startWatching
{
}
- (void)stopWatching
{
}
- (void)updatePathNotification:(NSNotification *)notification
{
}
@end @end

View file

@ -9,10 +9,12 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
@class PathNode; @class PathNode;
@class PathWatcher;
@interface FileTreeDataSource : NSObject { @interface FileTreeDataSource : NSObject {
PathNode *rootNode; PathNode *rootNode;
IBOutlet PathWatcher *watcher;
IBOutlet NSOutlineView *outlineView; IBOutlet NSOutlineView *outlineView;
} }

View file

@ -11,6 +11,7 @@
#import "DNDArrayController.h" #import "DNDArrayController.h"
#import "DirectoryNode.h" #import "DirectoryNode.h"
#import "PathWatcher.h"
@implementation FileTreeDataSource @implementation FileTreeDataSource
@ -48,14 +49,51 @@
- (void)setRootURL: (NSURL *)rootURL - (void)setRootURL: (NSURL *)rootURL
{ {
[[[[outlineView tableColumns] objectAtIndex:0] headerCell] setStringValue:[[NSFileManager defaultManager] displayNameAtPath:[rootURL path]]];
[rootNode release]; [rootNode release];
rootNode = [[DirectoryNode alloc] initWithDataSource:self url:rootURL]; rootNode = [[DirectoryNode alloc] initWithDataSource:self url:rootURL];
[watcher setPath:[rootURL path]];
[self reloadPathNode:rootNode]; [self reloadPathNode:rootNode];
} }
- (PathNode *)nodeForPath:(NSString *)path
{
NSString *relativePath = [path stringByReplacingOccurrencesOfString:[[[self rootURL] path] stringByAppendingString:@"/"] withString:@"" options:NSAnchoredSearch range:NSMakeRange(0, [path length])];
relativePath = [relativePath stringByStandardizingPath];
PathNode *theNode = rootNode;
NSLog(@"Root | Relative | Path: %@ | %@ | %@",[[self rootURL] path], relativePath, path);
for(NSString *c in [relativePath pathComponents])
{
NSLog(@"COMPONENT: %@", c);
BOOL found = NO;
for (PathNode *node in [theNode subpaths]) {
if ([[[[node url] path] lastPathComponent] isEqualToString:c]) {
theNode = node;
found = YES;
}
}
if (!found)
{
return nil;
}
NSLog(@"Component: %@", c);
}
return theNode;
}
- (void)pathDidChange:(NSString *)path
{
NSLog(@"PATH DID CHANGE: %@", path);
//Need to find the corresponding node...and call [node reloadPath], then [self reloadPathNode:node]
PathNode *node = [self nodeForPath:path];
NSLog(@"NODE IS: %@", node);
[node updatePath];
[self reloadPathNode:node];
}
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{ {
PathNode *n = (item == nil ? rootNode : item); PathNode *n = (item == nil ? rootNode : item);

View file

@ -37,8 +37,7 @@
- (BOOL)isLeaf; - (BOOL)isLeaf;
- (void)startWatching; - (void)updatePath;
- (void)stopWatching;
- (void)updatePathNotification:(NSNotification *)notification;
@end @end

View file

@ -12,8 +12,6 @@
#import "FileTreeDataSource.h" #import "FileTreeDataSource.h"
#import "UKKQueue.h"
#import "FileNode.h" #import "FileNode.h"
#import "DirectoryNode.h" #import "DirectoryNode.h"
#import "SmartFolderNode.h" #import "SmartFolderNode.h"
@ -59,49 +57,14 @@ NSURL *resolveAliases(NSURL *url)
} }
- (void)stopWatching
{
if (url)
{
NSLog(@"Stopped watching...: %@", [url path]);
//Remove all in one go
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
[[UKKQueue sharedFileWatcher] removePath:[url path]];
}
}
- (void)startWatching
{
if (url)
{
NSLog(@"WATCHING! %@", [url path]);
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(updatePathNotification:) name:UKFileWatcherRenameNotification object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(updatePathNotification:) name:UKFileWatcherWriteNotification object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(updatePathNotification:) name:UKFileWatcherDeleteNotification object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(updatePathNotification:) name:UKFileWatcherAttributeChangeNotification object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(updatePathNotification:) name:UKFileWatcherSizeIncreaseNotification object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(updatePathNotification:) name:UKFileWatcherLinkCountChangeNotification object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(updatePathNotification:) name:UKFileWatcherAccessRevocationNotification object:nil];
[[UKKQueue sharedFileWatcher] addPath:[url path]];
}
}
- (void)setURL:(NSURL *)u - (void)setURL:(NSURL *)u
{ {
[u retain]; [u retain];
[self stopWatching];
[url release]; [url release];
url = u; url = u;
[self startWatching];
[display release]; [display release];
display = [[NSFileManager defaultManager] displayNameAtPath:[url path]]; display = [[NSFileManager defaultManager] displayNameAtPath:[url path]];
[display retain]; [display retain];
@ -122,22 +85,6 @@ NSURL *resolveAliases(NSURL *url)
{ {
} }
- (void)updatePathNotification:(NSNotification *)notification
{
[self performSelectorOnMainThread:@selector(updatePathNotificationMainThread:) withObject:notification waitUntilDone:YES];
}
- (void)updatePathNotificationMainThread:(NSNotification *)notification
{
NSString *p = [[notification userInfo] objectForKey:@"path"];
if ([p isEqualToString:[url path]])
{
[self updatePath];
[dataSource reloadPathNode:self];
}
}
- (void)processPaths: (NSArray *)contents - (void)processPaths: (NSArray *)contents
{ {
NSMutableArray *newSubpaths = [[NSMutableArray alloc] init]; NSMutableArray *newSubpaths = [[NSMutableArray alloc] init];
@ -234,8 +181,6 @@ NSURL *resolveAliases(NSURL *url)
- (void)dealloc - (void)dealloc
{ {
[self stopWatching];
[url release]; [url release];
[icon release]; [icon release];

View file

@ -0,0 +1,31 @@
//
// PathWatcher.h
// Cog
//
// Created by Vincent Spader on 2/17/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#include <CoreServices/CoreServices.h>
@interface PathWatcher : NSObject {
FSEventStreamRef stream;
FSEventStreamContext *context;
IBOutlet id delegate;
}
- (void)setDelegate:(id)d;
- (id)delegate;
- (void)setPath:(NSString *)path; //Set the path to watch
- (void)cleanUp;
@end
@protocol PathWatcherDelegate
- (void)pathDidChange:(NSString *)path;
@end

View file

@ -0,0 +1,94 @@
//
// PathWatcher.m
// Cog
//
// Created by Vincent Spader on 2/17/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "PathWatcher.h"
static void myFSEventCallback(
ConstFSEventStreamRef streamRef,
void *clientCallBackInfo,
size_t numEvents,
void *eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[])
{
int i;
char **paths = eventPaths;
PathWatcher *pathWatcher = (PathWatcher *)clientCallBackInfo;
printf("Callback called\n");
for (i=0; i<numEvents; i++) {
NSString *pathString = [[NSString alloc] initWithUTF8String:paths[i]];
[[pathWatcher delegate] pathDidChange:pathString];
[pathString release];
}
}
@implementation PathWatcher
- (void)cleanUp
{
if (stream) {
FSEventStreamStop(stream);
FSEventStreamInvalidate(stream);
FSEventStreamRelease(stream);
stream = NULL;
}
if (context) {
free(context);
context = NULL;
}
}
- (void)setPath:(NSString *)path
{
[self cleanUp];
//Create FSEvent stream
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&path, 1, NULL);
context = (FSEventStreamContext*)malloc(sizeof(FSEventStreamContext));
context->version = 0;
context->info = (void *)self;
context->retain = NULL;
context->release = NULL;
// Create the stream, passing in a callback
stream = FSEventStreamCreate(NULL,
&myFSEventCallback,
context,
pathsToWatch,
kFSEventStreamEventIdSinceNow, // Or a previous event ID
1.0, //latency in seconds
kFSEventStreamCreateFlagNone // Watch this and all its subdirectories
);
FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
FSEventStreamStart(stream);
}
- (void)setDelegate:(id)d
{
[d retain];
[delegate release];
delegate = d;
}
- (id)delegate
{
return delegate;
}
- (void) dealloc
{
[self cleanUp];
[super dealloc];
}
@end

View file

@ -1,49 +0,0 @@
/* =============================================================================
FILE: UKFNSubscribeFileWatcher.m
PROJECT: Filie
COPYRIGHT: (c) 2005 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT License
REVISIONS:
2006-03-13 UK Commented, added singleton.
2005-03-02 UK Created.
========================================================================== */
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import <Cocoa/Cocoa.h>
#import "UKFileWatcher.h"
#import <Carbon/Carbon.h>
/*
NOTE: FNSubscribe has a built-in delay: If your application is in the
background while the changes happen, all notifications will be queued up
and sent to your app at once the moment it is brought to front again. If
your app really needs to do live updates in the background, use a KQueue
instead.
*/
// -----------------------------------------------------------------------------
// Class declaration:
// -----------------------------------------------------------------------------
@interface UKFNSubscribeFileWatcher : NSObject <UKFileWatcher>
{
id delegate; // Delegate must respond to UKFileWatcherDelegate protocol.
NSMutableDictionary* subscriptions; // List of FNSubscription pointers in NSValues, with the pathnames as their keys.
}
+(id) sharedFileWatcher;
// UKFileWatcher defines the methods: addPath: removePath: and delegate accessors.
// Private:
-(void) sendDelegateMessage: (FNMessage)message forSubscription: (FNSubscriptionRef)subscription;
@end

View file

@ -1,201 +0,0 @@
/* =============================================================================
FILE: UKFNSubscribeFileWatcher.m
PROJECT: Filie
COPYRIGHT: (c) 2005 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT License
REVISIONS:
2006-03-13 UK Commented, added singleton, added notifications.
2005-03-02 UK Created.
========================================================================== */
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import "UKFNSubscribeFileWatcher.h"
#import <Carbon/Carbon.h>
// -----------------------------------------------------------------------------
// Prototypes:
// -----------------------------------------------------------------------------
void UKFileSubscriptionProc(FNMessage message, OptionBits flags, void *refcon, FNSubscriptionRef subscription);
@implementation UKFNSubscribeFileWatcher
// -----------------------------------------------------------------------------
// sharedFileWatcher:
// Singleton accessor.
// -----------------------------------------------------------------------------
+(id) sharedFileWatcher
{
static UKFNSubscribeFileWatcher* sSharedFileWatcher = nil;
if( !sSharedFileWatcher )
sSharedFileWatcher = [[UKFNSubscribeFileWatcher alloc] init]; // This is a singleton, and thus an intentional "leak".
return sSharedFileWatcher;
}
// -----------------------------------------------------------------------------
// * CONSTRUCTOR:
// -----------------------------------------------------------------------------
-(id) init
{
self = [super init];
if( !self )
return nil;
subscriptions = [[NSMutableDictionary alloc] init];
return self;
}
// -----------------------------------------------------------------------------
// * DESTRUCTOR:
// -----------------------------------------------------------------------------
-(void) dealloc
{
NSEnumerator* enny = [subscriptions objectEnumerator];
NSValue* subValue = nil;
while( (subValue = [enny nextObject]) )
{
FNSubscriptionRef subscription = [subValue pointerValue];
FNUnsubscribe( subscription );
}
[subscriptions release];
[super dealloc];
}
// -----------------------------------------------------------------------------
// addPath:
// Start watching the object at the specified path. This only sends write
// notifications for all changes, as FNSubscribe doesn't tell what actually
// changed about our folder.
// -----------------------------------------------------------------------------
-(void) addPath: (NSString*)path
{
OSStatus err = noErr;
static FNSubscriptionUPP subscriptionUPP = NULL;
FNSubscriptionRef subscription = NULL;
if( !subscriptionUPP )
subscriptionUPP = NewFNSubscriptionUPP( UKFileSubscriptionProc );
err = FNSubscribeByPath( (UInt8*) [path fileSystemRepresentation], subscriptionUPP, (void*)self,
kNilOptions, &subscription );
if( err != noErr )
{
NSLog( @"UKFNSubscribeFileWatcher addPath: %@ failed due to error ID=%ld.", path, err );
return;
}
[subscriptions setObject: [NSValue valueWithPointer: subscription] forKey: path];
}
// -----------------------------------------------------------------------------
// removePath:
// Stop watching the object at the specified path.
// -----------------------------------------------------------------------------
-(void) removePath: (NSString*)path
{
NSValue* subValue = nil;
@synchronized( self )
{
subValue = [[[subscriptions objectForKey: path] retain] autorelease];
[subscriptions removeObjectForKey: path];
}
if( subValue )
{
FNSubscriptionRef subscription = [subValue pointerValue];
FNUnsubscribe( subscription );
}
}
// -----------------------------------------------------------------------------
// sendDelegateMessage:forSubscription:
// Bottleneck for change notifications. This is called by our callback
// function to actually inform the delegate and send out notifications.
//
// This *only* sends out write notifications, as FNSubscribe doesn't tell
// what changed about our folder.
// -----------------------------------------------------------------------------
-(void) sendDelegateMessage: (FNMessage)message forSubscription: (FNSubscriptionRef)subscription
{
NSValue* subValue = [NSValue valueWithPointer: subscription];
NSString* path = [[subscriptions allKeysForObject: subValue] objectAtIndex: 0];
[[[NSWorkspace sharedWorkspace] notificationCenter] postNotificationName: UKFileWatcherWriteNotification
object: self
userInfo: [NSDictionary dictionaryWithObjectsAndKeys: path, @"path", nil]];
[delegate watcher: self receivedNotification: UKFileWatcherWriteNotification forPath: path];
//NSLog( @"UKFNSubscribeFileWatcher noticed change to %@", path ); // DEBUG ONLY!
}
// -----------------------------------------------------------------------------
// delegate:
// Accessor for file watcher delegate.
// -----------------------------------------------------------------------------
-(id) delegate
{
return delegate;
}
// -----------------------------------------------------------------------------
// setDelegate:
// Mutator for file watcher delegate.
// -----------------------------------------------------------------------------
-(void) setDelegate: (id)newDelegate
{
delegate = newDelegate;
}
@end
// -----------------------------------------------------------------------------
// UKFileSubscriptionProc:
// Callback function we hand to Carbon so it can tell us when something
// changed about our watched folders. We set the refcon to a pointer to
// our object. This simply extracts the object and hands the info off to
// sendDelegateMessage:forSubscription: which does the actual work.
// -----------------------------------------------------------------------------
void UKFileSubscriptionProc( FNMessage message, OptionBits flags, void *refcon, FNSubscriptionRef subscription )
{
UKFNSubscribeFileWatcher* obj = (UKFNSubscribeFileWatcher*) refcon;
if( message == kFNDirectoryModifiedMessage ) // No others exist as of 10.4
[obj sendDelegateMessage: message forSubscription: subscription];
else
NSLog( @"UKFileSubscriptionProc: Unknown message %d", message );
}

View file

@ -1,62 +0,0 @@
/* =============================================================================
FILE: UKFileWatcher.h
PROJECT: Filie
COPYRIGHT: (c) 2005 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT License
REVISIONS:
2006-03-13 UK Moved notification constants to .m file.
2005-02-25 UK Created.
========================================================================== */
/*
This is a protocol that file change notification classes should adopt.
That way, no matter whether you use Carbon's FNNotify/FNSubscribe, BSD's
kqueue or whatever, the object being notified can react to change
notifications the same way, and you can easily swap one out for the other
to cater to different OS versions, target volumes etc.
*/
// -----------------------------------------------------------------------------
// Protocol:
// -----------------------------------------------------------------------------
@protocol UKFileWatcher
// +(id) sharedFileWatcher; // Singleton accessor. Not officially part of the protocol, but use this name if you provide a singleton.
-(void) addPath: (NSString*)path;
-(void) removePath: (NSString*)path;
-(id) delegate;
-(void) setDelegate: (id)newDelegate;
@end
// -----------------------------------------------------------------------------
// Methods delegates need to provide:
// -----------------------------------------------------------------------------
@interface NSObject (UKFileWatcherDelegate)
-(void) watcher: (id<UKFileWatcher>)kq receivedNotification: (NSString*)nm forPath: (NSString*)fpath;
@end
// Notifications this sends:
/* object = the file watcher object
userInfo.path = file path watched
These notifications are sent via the NSWorkspace notification center */
extern NSString* UKFileWatcherRenameNotification;
extern NSString* UKFileWatcherWriteNotification;
extern NSString* UKFileWatcherDeleteNotification;
extern NSString* UKFileWatcherAttributeChangeNotification;
extern NSString* UKFileWatcherSizeIncreaseNotification;
extern NSString* UKFileWatcherLinkCountChangeNotification;
extern NSString* UKFileWatcherAccessRevocationNotification;

View file

@ -1,38 +0,0 @@
/* =============================================================================
FILE: UKKQueue.m
PROJECT: Filie
COPYRIGHT: (c) 2005-06 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT License
REVISIONS:
2006-03-13 UK Created, moved notification constants here as exportable
symbols.
========================================================================== */
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import <Cocoa/Cocoa.h>
#import "UKFileWatcher.h"
// -----------------------------------------------------------------------------
// Constants:
// -----------------------------------------------------------------------------
// Do not rely on the actual contents of these constants. They will eventually
// be changed to be more generic and less KQueue-specific.
NSString* UKFileWatcherRenameNotification = @"UKKQueueFileRenamedNotification";
NSString* UKFileWatcherWriteNotification = @"UKKQueueFileWrittenToNotification";
NSString* UKFileWatcherDeleteNotification = @"UKKQueueFileDeletedNotification";
NSString* UKFileWatcherAttributeChangeNotification = @"UKKQueueFileAttributesChangedNotification";
NSString* UKFileWatcherSizeIncreaseNotification = @"UKKQueueFileSizeIncreasedNotification";
NSString* UKFileWatcherLinkCountChangeNotification = @"UKKQueueFileLinkCountChangedNotification";
NSString* UKFileWatcherAccessRevocationNotification = @"UKKQueueFileAccessRevocationNotification";

View file

@ -1,32 +0,0 @@
UKKQUEUE
--------
A wrapper class around the kqueue file change notification mechanism.
Simply create a UKKQueue (or use the singleton), add a few paths to it and listen to the change notifications via NSWorkspace's notification center.
LICENSE:
(c) 2003-06 by M. Uli Kusterer. You may redistribute, modify, use in
commercial products free of charge, however distributing modified copies
requires that you clearly mark them as having been modified by you, while
maintaining the original markings and copyrights. I don't like getting bug
reports about code I wasn't involved in.
I'd also appreciate if you gave credit in your app's about screen or a similar
place. A simple "Thanks to M. Uli Kusterer" is quite sufficient.
Also, I rarely turn down any postcards, gifts, complementary copies of
applications etc.
REVISION HISTORY:
0.1 - Initial release.
0.2 - Now calls delegate on main thread using UKMainThreadProxy, and checks retain count to make sure the object is released even when the thread is still holding on to it. Equivalent to SVN revision 79.
0.3 - Now adopts UKFileWatcher protocol to allow swapping out a kqueue for another scheme easily. Uses O_EVONLY instead of O_RDONLY to open the file without preventing it from being deleted or its drive ejected.
0.4 - Now includes UKFNSubscribeFileWatcher, and closes the kqueue file descriptor in a separate thread (thanks to Dominic Yu for the suggestion!) so you don't have to wait for close() to time out.
0.5 - Turns off all deprecated features. Changes the notifications to make it possible to subscribe to them more selectively. Changes notification constants to be safer for apps that expose KQueue to their plugins. FNSubscribeFileWatcher now also sends notifications (sorry, "write" only).
CONTACT:
Get the newest version at http://www.zathras.de
E-Mail me at witness (at) zathras (dot) de or witness (dot) of (dot) teachtext (at) gmx (dot) net

View file

@ -1,122 +0,0 @@
/* =============================================================================
FILE: UKKQueue.h
PROJECT: Filie
COPYRIGHT: (c) 2003 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT License
REVISIONS:
2006-03-13 UK Clarified license, streamlined UKFileWatcher stuff,
Changed notifications to be useful and turned off by
default some deprecated stuff.
2003-12-21 UK Created.
========================================================================== */
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import <Foundation/Foundation.h>
#include <sys/types.h>
#include <sys/event.h>
#import "UKFileWatcher.h"
// -----------------------------------------------------------------------------
// Constants:
// -----------------------------------------------------------------------------
// Backwards compatibility constants. Don't rely on code commented out with these constants, because it may be deleted in a future version.
#ifndef UKKQUEUE_BACKWARDS_COMPATIBLE
#define UKKQUEUE_BACKWARDS_COMPATIBLE 0 // 1 to send old-style kqueue:receivedNotification:forFile: messages to objects that accept them.
#endif
#ifndef UKKQUEUE_SEND_STUPID_NOTIFICATIONS
#define UKKQUEUE_SEND_STUPID_NOTIFICATIONS 0 // 1 to send old-style notifications that have the path as the object and no userInfo dictionary.
#endif
#ifndef UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME
#define UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME 0 // 1 to allow use of sharedQueue instead of sharedFileWatcher.
#endif
#ifndef UKKQUEUE_OLD_NOTIFICATION_NAMES
#define UKKQUEUE_OLD_NOTIFICATION_NAMES 0 // 1 to allow use of old KQueue-style notification names instead of the new more generic ones in UKFileWatcher.
#endif
// Flags for notifyingAbout:
#define UKKQueueNotifyAboutRename NOTE_RENAME // Item was renamed.
#define UKKQueueNotifyAboutWrite NOTE_WRITE // Item contents changed (also folder contents changed).
#define UKKQueueNotifyAboutDelete NOTE_DELETE // item was removed.
#define UKKQueueNotifyAboutAttributeChange NOTE_ATTRIB // Item attributes changed.
#define UKKQueueNotifyAboutSizeIncrease NOTE_EXTEND // Item size increased.
#define UKKQueueNotifyAboutLinkCountChanged NOTE_LINK // Item's link count changed.
#define UKKQueueNotifyAboutAccessRevocation NOTE_REVOKE // Access to item was revoked.
// Notifications this sends:
// (see UKFileWatcher)
// Old names: *deprecated*
#if UKKQUEUE_OLD_NOTIFICATION_NAMES
#define UKKQueueFileRenamedNotification UKFileWatcherRenameNotification
#define UKKQueueFileWrittenToNotification UKFileWatcherWriteNotification
#define UKKQueueFileDeletedNotification UKFileWatcherDeleteNotification
#define UKKQueueFileAttributesChangedNotification UKFileWatcherAttributeChangeNotification
#define UKKQueueFileSizeIncreasedNotification UKFileWatcherSizeIncreaseNotification
#define UKKQueueFileLinkCountChangedNotification UKFileWatcherLinkCountChangeNotification
#define UKKQueueFileAccessRevocationNotification UKFileWatcherAccessRevocationNotification
#endif
// -----------------------------------------------------------------------------
// UKKQueue:
// -----------------------------------------------------------------------------
@interface UKKQueue : NSObject <UKFileWatcher>
{
int queueFD; // The actual queue ID (Unix file descriptor).
NSMutableArray* watchedPaths; // List of NSStrings containing the paths we're watching.
NSMutableArray* watchedFDs; // List of NSNumbers containing the file descriptors we're watching.
id delegate; // Gets messages about changes instead of notification center, if specified.
id delegateProxy; // Proxy object to which we send messages so they reach delegate on the main thread.
BOOL alwaysNotify; // Send notifications even if we have a delegate? Defaults to NO.
BOOL keepThreadRunning; // Termination criterion of our thread.
}
+(id) sharedFileWatcher; // Returns a singleton, a shared kqueue object Handy if you're subscribing to the notifications. Use this, or just create separate objects using alloc/init. Whatever floats your boat.
-(int) queueFD; // I know you unix geeks want this...
// High-level file watching: (use UKFileWatcher protocol methods instead, where possible!)
-(void) addPathToQueue: (NSString*)path;
-(void) addPathToQueue: (NSString*)path notifyingAbout: (u_int)fflags;
-(void) removePathFromQueue: (NSString*)path;
-(id) delegate;
-(void) setDelegate: (id)newDelegate;
-(BOOL) alwaysNotify;
-(void) setAlwaysNotify: (BOOL)n;
#if UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME
+(UKKQueue*) sharedQueue;
#endif
// private:
-(void) watcherThread: (id)sender;
-(void) postNotification: (NSString*)nm forFile: (NSString*)fp; // Message-posting bottleneck.
@end
// -----------------------------------------------------------------------------
// Methods delegates need to provide:
// * DEPRECATED * use UKFileWatcher delegate methods instead!
// -----------------------------------------------------------------------------
@interface NSObject (UKKQueueDelegate)
-(void) kqueue: (UKKQueue*)kq receivedNotification: (NSString*)nm forFile: (NSString*)fpath;
@end

View file

@ -1,481 +0,0 @@
/* =============================================================================
FILE: UKKQueue.m
PROJECT: Filie
COPYRIGHT: (c) 2003 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT License
REVISIONS:
2006-03-13 UK Clarified license, streamlined UKFileWatcher stuff,
Changed notifications to be useful and turned off by
default some deprecated stuff.
2004-12-28 UK Several threading fixes.
2003-12-21 UK Created.
========================================================================== */
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import "UKKQueue.h"
#import "UKMainThreadProxy.h"
#import <unistd.h>
#import <fcntl.h>
// -----------------------------------------------------------------------------
// Macros:
// -----------------------------------------------------------------------------
// @synchronized isn't available prior to 10.3, so we use a typedef so
// this class is thread-safe on Panther but still compiles on older OSs.
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
#define AT_SYNCHRONIZED(n) @synchronized(n)
#else
#define AT_SYNCHRONIZED(n)
#endif
// -----------------------------------------------------------------------------
// Globals:
// -----------------------------------------------------------------------------
static UKKQueue * gUKKQueueSharedQueueSingleton = nil;
@implementation UKKQueue
// Deprecated:
#if UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME
+(UKKQueue*) sharedQueue
{
return [self sharedFileWatcher];
}
#endif
// -----------------------------------------------------------------------------
// sharedQueue:
// Returns a singleton queue object. In many apps (especially those that
// subscribe to the notifications) there will only be one kqueue instance,
// and in that case you can use this.
//
// For all other cases, feel free to create additional instances to use
// independently.
//
// REVISIONS:
// 2006-03-13 UK Renamed from sharedQueue.
// 2005-07-02 UK Created.
// -----------------------------------------------------------------------------
+(id) sharedFileWatcher
{
AT_SYNCHRONIZED( self )
{
if( !gUKKQueueSharedQueueSingleton )
gUKKQueueSharedQueueSingleton = [[UKKQueue alloc] init]; // This is a singleton, and thus an intentional "leak".
}
return gUKKQueueSharedQueueSingleton;
}
// -----------------------------------------------------------------------------
// * CONSTRUCTOR:
// Creates a new KQueue and starts that thread we use for our
// notifications.
//
// REVISIONS:
// 2004-11-12 UK Doesn't pass self as parameter to watcherThread anymore,
// because detachNewThreadSelector retains target and args,
// which would cause us to never be released.
// 2004-03-13 UK Documented.
// -----------------------------------------------------------------------------
-(id) init
{
self = [super init];
if( self )
{
queueFD = kqueue();
if( queueFD == -1 )
{
[self release];
return nil;
}
watchedPaths = [[NSMutableArray alloc] init];
watchedFDs = [[NSMutableArray alloc] init];
// Start new thread that fetches and processes our events:
keepThreadRunning = YES;
[NSThread detachNewThreadSelector:@selector(watcherThread:) toTarget:self withObject:nil];
}
return self;
}
// -----------------------------------------------------------------------------
// release:
// Since NSThread retains its target, we need this method to terminate the
// thread when we reach a retain-count of two. The thread is terminated by
// setting keepThreadRunning to NO.
//
// REVISIONS:
// 2004-11-12 UK Created.
// -----------------------------------------------------------------------------
-(oneway void) release
{
AT_SYNCHRONIZED(self)
{
//NSLog(@"%@ (%d)", self, [self retainCount]);
if( [self retainCount] == 2 && keepThreadRunning )
keepThreadRunning = NO;
}
[super release];
}
// -----------------------------------------------------------------------------
// * DESTRUCTOR:
// Releases the kqueue again.
//
// REVISIONS:
// 2004-03-13 UK Documented.
// -----------------------------------------------------------------------------
-(void) dealloc
{
delegate = nil;
[delegateProxy release];
if( keepThreadRunning )
keepThreadRunning = NO;
// Close all our file descriptors so the files can be deleted:
NSEnumerator* enny = [watchedFDs objectEnumerator];
NSNumber* fdNum;
while( (fdNum = [enny nextObject]) )
{
if( close( [fdNum intValue] ) == -1 )
NSLog(@"dealloc: Couldn't close file descriptor (%d)", errno);
}
[watchedPaths release];
watchedPaths = nil;
[watchedFDs release];
watchedFDs = nil;
[super dealloc];
//NSLog(@"kqueue released.");
}
// -----------------------------------------------------------------------------
// queueFD:
// Returns a Unix file descriptor for the KQueue this uses. The descriptor
// is owned by this object. Do not close it!
//
// REVISIONS:
// 2004-03-13 UK Documented.
// -----------------------------------------------------------------------------
-(int) queueFD
{
return queueFD;
}
// -----------------------------------------------------------------------------
// addPathToQueue:
// Tell this queue to listen for all interesting notifications sent for
// the object at the specified path. If you want more control, use the
// addPathToQueue:notifyingAbout: variant instead.
//
// REVISIONS:
// 2004-03-13 UK Documented.
// -----------------------------------------------------------------------------
-(void) addPathToQueue: (NSString*)path
{
[self addPath: path];
}
-(void) addPath: (NSString*)path
{
[self addPathToQueue: path notifyingAbout: UKKQueueNotifyAboutRename
| UKKQueueNotifyAboutWrite
| UKKQueueNotifyAboutDelete
| UKKQueueNotifyAboutAttributeChange];
}
// -----------------------------------------------------------------------------
// addPathToQueue:notfyingAbout:
// Tell this queue to listen for the specified notifications sent for
// the object at the specified path.
//
// REVISIONS:
// 2005-06-29 UK Files are now opened using O_EVTONLY instead of O_RDONLY
// which allows ejecting or deleting watched files/folders.
// Thanks to Phil Hargett for finding this flag in the docs.
// 2004-03-13 UK Documented.
// -----------------------------------------------------------------------------
-(void) addPathToQueue: (NSString*)path notifyingAbout: (u_int)fflags
{
struct timespec nullts = { 0, 0 };
struct kevent ev;
int fd = open( [path fileSystemRepresentation], O_EVTONLY, 0 );
if( fd >= 0 )
{
EV_SET( &ev, fd, EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_CLEAR,
fflags, 0, (void*)path );
AT_SYNCHRONIZED( self )
{
[watchedPaths addObject: path];
[watchedFDs addObject: [NSNumber numberWithInt: fd]];
kevent( queueFD, &ev, 1, NULL, 0, &nullts );
}
}
}
-(void) removePath: (NSString*)path
{
[self removePathFromQueue: path];
}
// -----------------------------------------------------------------------------
// removePathFromQueue:
// Stop listening for changes to the specified path. This removes all
// notifications. Use this to balance both addPathToQueue:notfyingAbout:
// as well as addPathToQueue:.
//
// REVISIONS:
// 2004-03-13 UK Documented.
// -----------------------------------------------------------------------------
-(void) removePathFromQueue: (NSString*)path
{
int index = 0;
int fd = -1;
AT_SYNCHRONIZED( self )
{
index = [watchedPaths indexOfObject: path];
if( index == NSNotFound )
return;
fd = [[watchedFDs objectAtIndex: index] intValue];
[watchedFDs removeObjectAtIndex: index];
[watchedPaths removeObjectAtIndex: index];
}
if( close( fd ) == -1 )
NSLog(@"removePathFromQueue: Couldn't close file descriptor (%d)", errno);
}
// -----------------------------------------------------------------------------
// removeAllPathsFromQueue:
// Stop listening for changes to all paths. This removes all
// notifications.
//
// REVISIONS:
// 2004-12-28 UK Added as suggested by bbum.
// -----------------------------------------------------------------------------
-(void) removeAllPathsFromQueue;
{
AT_SYNCHRONIZED( self )
{
NSEnumerator * fdEnumerator = [watchedFDs objectEnumerator];
NSNumber * anFD;
while( (anFD = [fdEnumerator nextObject]) != nil )
close( [anFD intValue] );
[watchedFDs removeAllObjects];
[watchedPaths removeAllObjects];
}
}
// -----------------------------------------------------------------------------
// watcherThread:
// This method is called by our NSThread to loop and poll for any file
// changes that our kqueue wants to tell us about. This sends separate
// notifications for the different kinds of changes that can happen.
// All messages are sent via the postNotification:forFile: main bottleneck.
//
// This also calls sharedWorkspace's noteFileSystemChanged.
//
// To terminate this method (and its thread), set keepThreadRunning to NO.
//
// REVISIONS:
// 2005-08-27 UK Changed to use keepThreadRunning instead of kqueueFD
// being -1 as termination criterion, and to close the
// queue in this thread so the main thread isn't blocked.
// 2004-11-12 UK Fixed docs to include termination criterion, added
// timeout to make sure the bugger gets disposed.
// 2004-03-13 UK Documented.
// -----------------------------------------------------------------------------
-(void) watcherThread: (id)sender
{
int n;
struct kevent ev;
struct timespec timeout = { 5, 0 }; // 5 seconds timeout.
int theFD = queueFD; // So we don't have to risk accessing iVars when the thread is terminated.
while( keepThreadRunning )
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NS_DURING
n = kevent( queueFD, NULL, 0, &ev, 1, &timeout );
if( n > 0 )
{
if( ev.filter == EVFILT_VNODE )
{
if( ev.fflags )
{
NSString* fpath = [[(NSString *)ev.udata retain] autorelease]; // In case one of the notified folks removes the path.
//NSLog(@"UKKQueue: Detected file change: %@ %i", fpath, fpath);
[[NSWorkspace sharedWorkspace] noteFileSystemChanged: fpath];
//NSLog(@"ev.flags = %u",ev.fflags); // DEBUG ONLY!
if( (ev.fflags & NOTE_RENAME) == NOTE_RENAME )
[self postNotification: UKFileWatcherRenameNotification forFile: fpath];
if( (ev.fflags & NOTE_WRITE) == NOTE_WRITE )
[self postNotification: UKFileWatcherWriteNotification forFile: fpath];
if( (ev.fflags & NOTE_DELETE) == NOTE_DELETE )
[self postNotification: UKFileWatcherDeleteNotification forFile: fpath];
if( (ev.fflags & NOTE_ATTRIB) == NOTE_ATTRIB )
[self postNotification: UKFileWatcherAttributeChangeNotification forFile: fpath];
if( (ev.fflags & NOTE_EXTEND) == NOTE_EXTEND )
[self postNotification: UKFileWatcherSizeIncreaseNotification forFile: fpath];
if( (ev.fflags & NOTE_LINK) == NOTE_LINK )
[self postNotification: UKFileWatcherLinkCountChangeNotification forFile: fpath];
if( (ev.fflags & NOTE_REVOKE) == NOTE_REVOKE )
[self postNotification: UKFileWatcherAccessRevocationNotification forFile: fpath];
}
}
}
NS_HANDLER
NSLog(@"Error in UKKQueue watcherThread: %@",localException);
NS_ENDHANDLER
[pool release];
}
// Close our kqueue's file descriptor:
if( close( theFD ) == -1 )
NSLog(@"release: Couldn't close main kqueue (%d)", errno);
//NSLog(@"exiting kqueue watcher thread.");
}
// -----------------------------------------------------------------------------
// postNotification:forFile:
// This is the main bottleneck for posting notifications. If you don't want
// the notifications to go through NSWorkspace, override this method and
// send them elsewhere.
//
// REVISIONS:
// 2004-02-27 UK Changed this to send new notification, and the old one
// only to objects that respond to it. The old category on
// NSObject could cause problems with the proxy itself.
// 2004-10-31 UK Helloween fun: Make this use a mainThreadProxy and
// allow sending the notification even if we have a
// delegate.
// 2004-03-13 UK Documented.
// -----------------------------------------------------------------------------
-(void) postNotification: (NSString*)nm forFile: (NSString*)fp
{
if( delegateProxy )
{
#if UKKQUEUE_BACKWARDS_COMPATIBLE
if( ![delegateProxy respondsToSelector: @selector(watcher:receivedNotification:forPath:)] )
[delegateProxy kqueue: self receivedNotification: nm forFile: fp];
else
#endif
[delegateProxy watcher: self receivedNotification: nm forPath: fp];
}
if( !delegateProxy || alwaysNotify )
{
#if UKKQUEUE_SEND_STUPID_NOTIFICATIONS
[[[NSWorkspace sharedWorkspace] notificationCenter] postNotificationName: nm object: fp];
#else
[[[NSWorkspace sharedWorkspace] notificationCenter] postNotificationName: nm object: self
userInfo: [NSDictionary dictionaryWithObjectsAndKeys: fp, @"path", nil]];
#endif
}
}
-(id) delegate
{
return delegate;
}
-(void) setDelegate: (id)newDelegate
{
id oldProxy = delegateProxy;
delegate = newDelegate;
delegateProxy = [delegate copyMainThreadProxy];
[oldProxy release];
}
// -----------------------------------------------------------------------------
// Flag to send a notification even if we have a delegate:
// -----------------------------------------------------------------------------
-(BOOL) alwaysNotify
{
return alwaysNotify;
}
-(void) setAlwaysNotify: (BOOL)n
{
alwaysNotify = n;
}
// -----------------------------------------------------------------------------
// description:
// This method can be used to help in debugging. It provides the value
// used by NSLog & co. when you request to print this object using the
// %@ format specifier.
//
// REVISIONS:
// 2004-11-12 UK Created.
// -----------------------------------------------------------------------------
-(NSString*) description
{
return [NSString stringWithFormat: @"%@ { watchedPaths = %@, alwaysNotify = %@ }", NSStringFromClass([self class]), watchedPaths, (alwaysNotify? @"YES" : @"NO") ];
}
@end

View file

@ -1,56 +0,0 @@
/* =============================================================================
FILE: UKMainThreadProxy.h
PROJECT: UKMainThreadProxy
PURPOSE: Send a message to object theObject to [theObject mainThreadProxy]
instead and the message will be received on the main thread by
theObject.
COPYRIGHT: (c) 2004 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT License
REVISIONS:
2006-03-13 UK Clarified license.
2004-10-14 UK Created.
========================================================================== */
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import <Cocoa/Cocoa.h>
// -----------------------------------------------------------------------------
// Categories:
// -----------------------------------------------------------------------------
@interface NSObject (UKMainThreadProxy)
-(id) mainThreadProxy; // You can't init or release this object.
-(id) copyMainThreadProxy; // Gives you a retained version.
@end
// -----------------------------------------------------------------------------
// Classes:
// -----------------------------------------------------------------------------
/*
This object is created as a proxy in a second thread for an existing object.
All messages you send to this object will automatically be sent to the other
object on the main thread, except NSObject methods like retain/release etc.
*/
@interface UKMainThreadProxy : NSObject
{
IBOutlet id target;
}
-(id) initWithTarget: (id)targ;
@end

View file

@ -1,151 +0,0 @@
/* =============================================================================
FILE: UKMainThreadProxy.h
PROJECT: UKMainThreadProxy
PURPOSE: Send a message to object theObject to [theObject mainThreadProxy]
instead and the message will be received on the main thread by
theObject.
COPYRIGHT: (c) 2004 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT Licenseâ
REVISIONS:
2006-03-13 UK Clarified license.
2004-10-14 UK Created.
========================================================================== */
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import "UKMainThreadProxy.h"
@implementation UKMainThreadProxy
-(id) initWithTarget: (id)targ
{
self = [super init];
if( self )
target = targ;
return self;
}
// -----------------------------------------------------------------------------
// Introspection overrides:
// -----------------------------------------------------------------------------
-(BOOL) respondsToSelector: (SEL)itemAction
{
BOOL does = [super respondsToSelector: itemAction];
return( does || [target respondsToSelector: itemAction] );
}
-(id) performSelector: (SEL)itemAction
{
BOOL does = [super respondsToSelector: itemAction];
if( does )
return [super performSelector: itemAction];
if( ![target respondsToSelector: itemAction] )
[self doesNotRecognizeSelector: itemAction];
[target retain];
[target performSelectorOnMainThread: itemAction withObject: nil waitUntilDone: YES];
[target release];
return nil;
}
-(id) performSelector: (SEL)itemAction withObject: (id)obj
{
BOOL does = [super respondsToSelector: itemAction];
if( does )
return [super performSelector: itemAction withObject: obj];
if( ![target respondsToSelector: itemAction] )
[self doesNotRecognizeSelector: itemAction];
[target retain];
[obj retain];
[target performSelectorOnMainThread: itemAction withObject: obj waitUntilDone: YES];
[obj release];
[target release];
return nil;
}
// -----------------------------------------------------------------------------
// Forwarding unknown methods to the target:
// -----------------------------------------------------------------------------
-(NSMethodSignature*) methodSignatureForSelector: (SEL)itemAction
{
NSMethodSignature* sig = [super methodSignatureForSelector: itemAction];
if( sig )
return sig;
return [target methodSignatureForSelector: itemAction];
}
-(void) forwardInvocation: (NSInvocation*)invocation
{
SEL itemAction = [invocation selector];
if( [target respondsToSelector: itemAction] )
{
[invocation retainArguments];
[target retain];
[invocation performSelectorOnMainThread: @selector(invokeWithTarget:) withObject: target waitUntilDone: YES];
[target release];
}
else
[self doesNotRecognizeSelector: itemAction];
}
// -----------------------------------------------------------------------------
// Safety net:
// -----------------------------------------------------------------------------
-(id) mainThreadProxy // Just in case someone accidentally sends this message to a main thread proxy.
{
return self;
}
-(id) copyMainThreadProxy // Just in case someone accidentally sends this message to a main thread proxy.
{
return [self retain];
}
@end
// -----------------------------------------------------------------------------
// Shorthand notation for getting a main thread proxy:
// -----------------------------------------------------------------------------
@implementation NSObject (UKMainThreadProxy)
-(id) mainThreadProxy
{
return [[[UKMainThreadProxy alloc] initWithTarget: self] autorelease];
}
-(id) copyMainThreadProxy
{
return [[UKMainThreadProxy alloc] initWithTarget: self];
}
@end