Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest Download improvements #1109

Merged
merged 5 commits into from Sep 20, 2012
Merged

Latest Download improvements #1109

merged 5 commits into from Sep 20, 2012

Conversation

skurfer
Copy link
Member

@skurfer skurfer commented Sep 12, 2012

This is mainly to fix #1102, but there are some other small improvements as described in the commits.

skurfer added 2 commits Sep 12, 2012
other small improvements:
* set `downloadPath` *before* it gets used in error messages
* use a set to ignore certain extensions
* use the OS default as a fallback instead of hard-coding `~/Downloads`
@skurfer
Copy link
Member Author

@skurfer skurfer commented Sep 13, 2012

You're probably right that it's Safari 6 and not the OS. I checked Time Machine for my Safari 5 prefs thinking we could use the absence of the DownloadsPath key to decide which to use, but it's actually there, so we can just use that in all cases.

Somewhat unrelated, but have you noticed that resolveProxyObject: gets called 12 times when you call up the object? Probably something we should look into. :-)

@pjrobertson
Copy link
Member

@pjrobertson pjrobertson commented Sep 13, 2012

Somewhat unrelated, but have you noticed that resolveProxyObject: gets called 12 times when you call up the object? Probably something we should look into. :-)

Yep. It gets called for things like hasChildren, then loadIcon then all
the other bits and bobs… good isn't it? :P

On 13 September 2012 03:33, Rob McBroom notifications@github.com wrote:

You're probably right that it's Safari 6 and not the OS. I checked Time
Machine for my Safari 5 prefs thinking we could use the absence of the
DownloadsPath key to decide which to use, but it's actually there, so we
can just use that in all cases.

Somewhat unrelated, but have you noticed that resolveProxyObject: gets
called 12 times when you call up the object? Probably something we
should look into. :-)


Reply to this email directly or view it on GitHubhttps://github.com//pull/1109#issuecomment-8516640.

@tiennou
Copy link
Member

@tiennou tiennou commented Sep 13, 2012

That's weird, there's a 3 seconds cache for that normally... Does it happen for every proxy or just the Last Download one ?

@skurfer
Copy link
Member Author

@skurfer skurfer commented Sep 13, 2012

On the last test, it only fired twice. I should have looked at the stack trace to see what was calling it, but I was more interested in the problem at hand. :-)

I'll look into it a bit.

By the way, I added another commit to this last night, so let me know if there are outstanding issues.

@skurfer
Copy link
Member Author

@skurfer skurfer commented Sep 13, 2012

Still a mystery. It's definitely being called multiple times. Since the cache is stored on self, I thought there might be multiple instances getting created somehow, but as you can see from the logs below, the memory address is the same.

I added some NSLogs so my clicking in the debugger wouldn't affect the cache timer. This is the result of calling up Latest Download, Current Web Page, then IP Address one time each.

2012-09-13 13:54:23.001 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.001 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.002 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.002 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.109 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.110 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.110 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.111 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.112 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.112 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.112 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.113 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.113 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.114 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.114 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.114 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.121 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.121 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.122 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.122 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.123 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.123 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.123 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.124 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.134 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.135 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.136 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.136 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.138 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.139 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.139 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.139 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.140 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.140 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.140 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.141 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.152 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.153 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.153 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.153 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.162 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.163 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.163 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.163 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.164 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.164 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.165 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.165 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.165 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.184 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.184 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.184 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.185 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.185 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.186 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.186 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.187 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.187 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.187 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.187 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.188 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.188 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.188 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:23.189 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106ec4850>, QSMostRecentDownloadProxy
2012-09-13 13:54:29.859 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.859 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.860 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.860 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.878 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.879 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.879 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.879 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.880 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.880 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.880 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.881 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.881 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.881 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.882 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.882 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.882 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.883 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.883 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:29.883 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eb9ed0>, QSSafariFrontPageProxy
2012-09-13 13:54:32.230 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106eba700>, QSNetworkIPAddressProxy
2012-09-13 13:54:32.231 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106eba700>, QSNetworkIPAddressProxy
2012-09-13 13:54:32.232 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106eba700>, QSNetworkIPAddressProxy
2012-09-13 13:54:32.232 Quicksilver[90247:303] storing proxy to cache: QSProxyObject <0x106eba700>, QSNetworkIPAddressProxy
2012-09-13 13:54:35.030 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eba700>, QSNetworkIPAddressProxy
2012-09-13 13:54:35.031 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eba700>, QSNetworkIPAddressProxy
2012-09-13 13:54:35.031 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eba700>, QSNetworkIPAddressProxy
2012-09-13 13:54:35.032 Quicksilver[90247:303] returning proxy from cache: QSProxyObject <0x106eba700>, QSNetworkIPAddressProxy

That's as far as I'm going to take it for now.

@tiennou
Copy link
Member

@tiennou tiennou commented Sep 14, 2012

Okay, I put appropriate breakpoints and got it to work. You just need to remove the [self releaseProxy] in the -(void)becameSelected method (remove the method, it's defined to do nothing on QSBasicObject), because that makes no sense ;-). Then be extra cautious with NSLogging proxy objects, because the -respondsToSelector: method will trigger the resolution for -description, which triggers a loop if you're doing it in either -resolveProxyObject: or -releaseProxy, keeping timers firing like crazy until you deselect the proxy from the interface (My workaround was to log [self name] instead of self to prevent that, but since that's only for debugging I don't know if that's so useful.).

BTW, I also took some time to check QSDownloads behavior here, and I think using the download path from Internet Config is wrong (at least here it points to a years old location to a now non-existent path, and thus fails to resolve every time). The correct location is now under DownloadPath in Safari's preferences file, but I have no idea when did this change, and the fact that I'm using Chrome and that we aren't checking if the setting is the same makes me think this should be handled by the Browser mediator instead of being hardcoded here.

BTW 2, there's a - (NSString *)internetDownloadLocation in QSController that now looks suspicious to me ;-).

@skurfer
Copy link
Member Author

@skurfer skurfer commented Sep 14, 2012

You just need to remove the [self releaseProxy] in the -(void)becameSelected method (remove the method, it's defined to do nothing on QSBasicObject)

OK, I'll try that.

Then be extra cautious with NSLogging proxy objects

Good point. I was calling self, which may have triggered extra calls.

I also took some time to check QSDownloads behavior here, and I think using the download path from Internet Config is wrong

As of the most recent commit, it no longer uses Internet Config at all.

…makes me think this should be handled by the Browser mediator instead of being hardcoded here.

I agree, but for this pull request, I'm just trying to get what was already there to work again. :-)

BTW 2, there's a - (NSString *)internetDownloadLocation in QSController that now looks suspicious to me ;-).

I'll look into that. It should probably be removed or updated and moved to the QSDownloads class.

@skurfer
Copy link
Member Author

@skurfer skurfer commented Sep 17, 2012

Two new commits. Let me know what you think.

@skurfer
Copy link
Member Author

@skurfer skurfer commented Sep 17, 2012

I can't find any other calls to internetDownloadLocation. I admit I forgot to check until you brought it up.

As for becameSelected, git blame says… What else? "Code cleanup"! It was probably meant to wipe out the cached version of the proxy as soon as you "use" it, but it was just too aggressive. I've tried different proxies and haven't been able to cause problems, but yeah, we should test it for a while.

@tiennou
Copy link
Member

@tiennou tiennou commented Sep 18, 2012

Looks good to me. I think the -becameSelected thing ought to make sure the proxy doesn't get used while it points to an older value: imagine a proxy for Current Time, it would be 0-3 seconds late, depending on the time you took to execute. And it looks like I'm right, because -[QSAction performOnDirectObject:indirectObject:] doesn't make sure it's up to date.

On an almost completely unrelated note, I'm finding the various checks to resolve QSProxyObject and QSRankedObject intrusive. What do you think of adding a -resolvedObject to QSRankedObject and just call that every time you need to make sure they are resolved (like in QSBasicObject -isEqual:) ? That would make all those -isKindOf: checks unnecessary.

@skurfer
Copy link
Member Author

@skurfer skurfer commented Sep 18, 2012

I think the -becameSelected thing ought to make sure the proxy doesn't get used while it points to an older value: imagine a proxy for Current Time, it would be 0-3 seconds late, depending on the time you took to execute.

OK, but short of resolving it, how do we get it up to date? And if we resolve it, aren't we just reintroducing the same problem? I think 3 seconds is an acceptable age for a proxy. And if a particular object needs to be guaranteed fresh (like Current Time), the object source can implement cacheTimeForProxy: to override the 3 second default. QSProcessMonitor does this.

And it looks like I'm right, because -[QSAction performOnDirectObject:indirectObject:] doesn't make sure it's up to date.

I think it does. It calls [dObject resolvedObject] before running the action. That will cause the object to be updated (if the cache is expired).

On an almost completely unrelated note, I'm finding the various checks to resolve QSProxyObject and QSRankedObject intrusive.

I see 6 calls to isKindOfClass:[QSProxyObject class] and 12 for QSRankedObject. If you added resolvedObject to QSRankedObject, what would it do differently from the existing object method on that class? And how would you know to run it without checking the kind of class first? (Sorry if I'm missing the obvious.)

@tiennou
Copy link
Member

@tiennou tiennou commented Sep 18, 2012

I think it does. It calls [dObject resolvedObject] before running the action. That will cause the object to be updated (if the cache is expired).

Which was my 3 seconds point ;-). I'd say -releaseProxy there before -resolvedObject. Only problem I can think of is the object changing between what was shown and what is going to be executed. But since you're actually still looking at QS at that point the interference might be minimal.

I see 6 calls to isKindOfClass:[QSProxyObject class] and 12 for QSRankedObject. If you added resolvedObject to QSRankedObject, what would it do differently from the existing object method on that class? And how would you know to run it without checking the kind of class first? (Sorry if I'm missing the obvious.)

Then when you got your hands on a QSObject, you'd call -resolvedObject on it and you would be sure that you have a real object, and not either a QSProxyObject or a QSRankedObject. And you don't need to know, since QSBasicObject returns self. It's just that you'd have a "quacks like a duck, it must be a duck".

@skurfer
Copy link
Member Author

@skurfer skurfer commented Sep 18, 2012

Which was my 3 seconds point ;-). I'd say -releaseProxy there before -resolvedObject.

It's only going to be 3 seconds if the object source says that's an acceptable lag (implicitly, by not overriding it). If it needs to be less, the option is there, so I really think it's fine how it is. Unless you think the only purpose of the cache is to prevent repeated calls in the interface, and not to generally cache in all circumstances. In that case, I can see your point, but I'm not sure it's worth it.

Plus I think this could be problematic for some proxies. For example, "Current Selection" doesn't seem to work unless you get it from the cache. That is, you have to “use” it within 3 seconds of calling it or it loses its contents. If it were reset unconditionally, it would never work.

Only problem I can think of is the object changing between what was shown and what is going to be executed. But since you're actually still looking at QS at that point the interference might be minimal.

True, but in almost all cases, you don't really get shown anything unless you arrow into it, and at that point, I think you're dealing with the child object, which shouldn't change. But there are other concerns, as I've said. :-)

Then when you got your hands on a QSObject, you'd call -resolvedObject on it and you would be sure that you have a real object, and not either a QSProxyObject or a QSRankedObject.

Ah, OK. So we could call it blindly all over the place. I agree. We should do it.

pjrobertson added a commit that referenced this issue Sep 20, 2012
Latest Download improvements
@pjrobertson pjrobertson merged commit f60af99 into quicksilver:master Sep 20, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants