]> git.saurik.com Git - cydia.git/blobdiff - Cydia.mm
The syslog is more useful.
[cydia.git] / Cydia.mm
index 71a57df9b256cd2a280c60ec0751482bc50c46f6..eecc2be430332940f09eabd28c00dcbbd65091de 100644 (file)
--- a/Cydia.mm
+++ b/Cydia.mm
@@ -41,6 +41,7 @@
 /* #include Directives {{{ */
 #import "UICaboodle.h"
 
+#include <objc/message.h>
 #include <objc/objc.h>
 #include <objc/runtime.h>
 
@@ -55,6 +56,7 @@
 // XXX: remove
 #import <MessageUI/MailComposeController.h>
 
+#include <iomanip>
 #include <sstream>
 #include <string>
 
@@ -114,14 +116,71 @@ bool _itv;
         exit(0); \
 } while (false)
 
-static uint64_t profile_;
-
 #define _timestamp ({ \
     struct timeval tv; \
     gettimeofday(&tv, NULL); \
     tv.tv_sec * 1000000 + tv.tv_usec; \
 })
 
+typedef std::vector<class ProfileTime *> TimeList;
+TimeList times_;
+
+class ProfileTime {
+  private:
+    const char *name_;
+    uint64_t total_;
+    uint64_t count_;
+
+  public:
+    ProfileTime(const char *name) :
+        name_(name),
+        total_(0)
+    {
+        times_.push_back(this);
+    }
+
+    void AddTime(uint64_t time) {
+        total_ += time;
+        ++count_;
+    }
+
+    void Print() {
+        if (total_ != 0)
+            std::cerr << std::setw(5) << count_ << ", " << std::setw(7) << total_ << " : " << name_ << std::endl;
+        total_ = 0;
+        count_ = 0;
+    }
+};
+
+class ProfileTimer {
+  private:
+    ProfileTime &time_;
+    uint64_t start_;
+
+  public:
+    ProfileTimer(ProfileTime &time) :
+        time_(time),
+        start_(_timestamp)
+    {
+    }
+
+    ~ProfileTimer() {
+        time_.AddTime(_timestamp - start_);
+    }
+};
+
+void PrintTimes() {
+    for (TimeList::const_iterator i(times_.begin()); i != times_.end(); ++i)
+        (*i)->Print();
+    std::cerr << "========" << std::endl;
+}
+
+#define _profile(name) { \
+    static ProfileTime name(#name); \
+    ProfileTimer _ ## name(name);
+
+#define _end }
+
 /* Objective-C Handle<> {{{ */
 template <typename Type_>
 class _H {
@@ -172,7 +231,72 @@ void NSLogRect(const char *fix, const CGRect &rect) {
     NSLog(@"%s(%g,%g)+(%g,%g)", fix, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
 }
 
+@interface NSObject (Cydia)
+- (id) yieldToSelector:(SEL)selector withObject:(id)object;
+- (id) yieldToSelector:(SEL)selector;
+@end
+
+@implementation NSObject (Cydia)
+
+- (void) doNothing {
+}
+
+- (void) _yieldToContext:(NSMutableArray *)context { _pooled
+    SEL selector(reinterpret_cast<SEL>([[context objectAtIndex:0] pointerValue]));
+    id object([[context objectAtIndex:1] nonretainedObjectValue]);
+    volatile bool &stopped(*reinterpret_cast<bool *>([[context objectAtIndex:2] pointerValue]));
+
+    /* XXX: deal with exceptions */
+    id value([self performSelector:selector withObject:object]);
+
+    [context removeAllObjects];
+    if (value != nil)
+        [context addObject:value];
+
+    stopped = true;
+
+    [self
+        performSelectorOnMainThread:@selector(doNothing)
+        withObject:nil
+        waitUntilDone:NO
+    ];
+}
+
+- (id) yieldToSelector:(SEL)selector withObject:(id)object {
+    /*return [self performSelector:selector withObject:object];*/
+
+    volatile bool stopped(false);
+
+    NSMutableArray *context([NSMutableArray arrayWithObjects:
+        [NSValue valueWithPointer:selector],
+        [NSValue valueWithNonretainedObject:object],
+        [NSValue valueWithPointer:const_cast<bool *>(&stopped)],
+    nil]);
+
+    NSThread *thread([[[NSThread alloc]
+        initWithTarget:self
+        selector:@selector(_yieldToContext:)
+        object:context
+    ] autorelease]);
+
+    [thread start];
+
+    NSRunLoop *loop([NSRunLoop currentRunLoop]);
+    NSDate *future([NSDate distantFuture]);
+
+    while (!stopped && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
+
+    return [context count] == 0 ? nil : [context objectAtIndex:0];
+}
+
+- (id) yieldToSelector:(SEL)selector {
+    return [self yieldToSelector:selector withObject:nil];
+}
+
+@end
+
 /* NSForcedOrderingSearch doesn't work on the iPhone */
+static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch;
 static const NSStringCompareOptions BaseCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch;
 static const NSStringCompareOptions ForcedCompareOptions_ = BaseCompareOptions_;
 static const NSStringCompareOptions LaxCompareOptions_ = BaseCompareOptions_ | NSCaseInsensitiveSearch;
@@ -229,18 +353,13 @@ extern NSString * const kCAFilterNearest;
 
 @implementation PopTransitionView
 
-- (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to {
+- (void) transitionViewDidComplete:(UITransitionView *)view fromView:(UIView *)from toView:(UIView *)to {
     if (from != nil && to == nil)
         [self removeFromSuperview];
 }
 
 @end
 
-@interface UIView (PopUpView)
-- (void) popFromSuperviewAnimated:(BOOL)animated;
-- (void) popSubview:(UIView *)view;
-@end
-
 @implementation UIView (PopUpView)
 
 - (void) popFromSuperviewAnimated:(BOOL)animated {
@@ -262,11 +381,24 @@ extern NSString * const kCAFilterNearest;
 
 #define lprintf(args...) fprintf(stderr, args)
 
-#define ForRelease 0
-#define ForSaurik (1 && !ForRelease)
+#define ForRelease 1
+#define ForSaurik (0 && !ForRelease)
+#define LogBrowser (1 && !ForRelease)
+#define ManualRefresh (1 && !ForRelease)
+#define ShowInternals (1 && !ForRelease)
 #define IgnoreInstall (0 && !ForRelease)
 #define RecycleWebViews 0
-#define AlwaysReload (1 && !ForRelease)
+#define AlwaysReload (0 && !ForRelease)
+
+#if ForRelease
+#undef _trace
+#define _trace(args...)
+#undef _profile
+#define _profile(name) {
+#undef _end
+#define _end }
+#define PrintTimes() do {} while (false)
+#endif
 
 /* Radix Sort {{{ */
 @interface NSMutableArray (Radix)
@@ -403,12 +535,19 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s
 @end
 
 @interface NSString (Cydia)
++ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length;
 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length;
 - (NSComparisonResult) compareByPath:(NSString *)other;
+- (NSString *) stringByCachingURLWithCurrentCDN;
+- (NSString *) stringByAddingPercentEscapesIncludingReserved;
 @end
 
 @implementation NSString (Cydia)
 
++ (NSString *) stringWithUTF8BytesNoCopy:(const char *)bytes length:(int)length {
+    return [[[NSString alloc] initWithBytesNoCopy:const_cast<char *>(bytes) length:length encoding:NSUTF8StringEncoding freeWhenDone:NO] autorelease];
+}
+
 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
     return [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease];
 }
@@ -443,6 +582,26 @@ NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *s
     return result == NSOrderedSame ? value : result;
 }
 
+- (NSString *) stringByCachingURLWithCurrentCDN {
+    return [self
+        stringByReplacingOccurrencesOfString:@"://"
+        withString:@"://ne.edgecastcdn.net/8003A4/"
+        options:0
+        /* XXX: this is somewhat inaccurate */
+        range:NSMakeRange(0, 10)
+    ];
+}
+
+- (NSString *) stringByAddingPercentEscapesIncludingReserved {
+    return [(id)CFURLCreateStringByAddingPercentEscapes(
+        kCFAllocatorDefault, 
+        (CFStringRef) self,
+        NULL,
+        CFSTR(";/?:@&=+$,"),
+        kCFStringEncodingUTF8
+    ) autorelease];
+}
+
 @end
 
 /* Perl-Compatible RegEx {{{ */
@@ -500,6 +659,8 @@ class Pcre {
 - (NSString *) name;
 - (NSString *) address;
 
+- (void) setAddress:(NSString *)address;
+
 + (Address *) addressWithString:(NSString *)string;
 - (Address *) initWithString:(NSString *)string;
 @end
@@ -521,6 +682,15 @@ class Pcre {
     return address_;
 }
 
+- (void) setAddress:(NSString *)address {
+    if (address_ != nil)
+        [address_ autorelease];
+    if (address == nil)
+        address_ = nil;
+    else
+        address_ = [address retain];
+}
+
 + (Address *) addressWithString:(NSString *)string {
     return [[[Address alloc] initWithString:string] autorelease];
 }
@@ -605,21 +775,27 @@ static const float KeyboardTime_ = 0.3f;
 #define SandboxTemplate_ "/usr/share/sandbox/SandboxTemplate.sb"
 #define NotifyConfig_ "/etc/notify.conf"
 
+static bool Queuing_;
+
 static CGColor Blue_;
 static CGColor Blueish_;
 static CGColor Black_;
 static CGColor Off_;
 static CGColor White_;
 static CGColor Gray_;
+static CGColor Green_;
+static CGColor Purple_;
+static CGColor Purplish_;
+
+static UIColor *InstallingColor_;
+static UIColor *RemovingColor_;
 
 static NSString *App_;
 static NSString *Home_;
 static BOOL Sounds_Keyboard_;
 
 static BOOL Advanced_;
-#if !ForSaurik
 static BOOL Loaded_;
-#endif
 static BOOL Ignored_;
 
 static UIFont *Font12_;
@@ -631,6 +807,8 @@ static UIFont *Font22Bold_;
 static const char *Machine_ = NULL;
 static const NSString *UniqueID_ = nil;
 static const NSString *Build_ = nil;
+static const NSString *Product_ = nil;
+static const NSString *Safari_ = nil;
 
 CFLocaleRef Locale_;
 CGColorSpaceRef space_;
@@ -640,7 +818,6 @@ bool reload_;
 
 static NSDictionary *SectionMap_;
 static NSMutableDictionary *Metadata_;
-static NSMutableDictionary *Indices_;
 static _transient NSMutableDictionary *Settings_;
 static _transient NSString *Role_;
 static _transient NSMutableDictionary *Packages_;
@@ -754,6 +931,7 @@ bool isSectionVisible(NSString *section) {
 @end
 
 @protocol CydiaDelegate
+- (void) clearPackage:(Package *)package;
 - (void) installPackage:(Package *)package;
 - (void) removePackage:(Package *)package;
 - (void) slideUp:(UIActionSheet *)alert;
@@ -762,6 +940,7 @@ bool isSectionVisible(NSString *section) {
 - (void) syncData;
 - (void) askForSettings;
 - (UIProgressHUD *) addProgressHUD;
+- (void) removeProgressHUD:(UIProgressHUD *)hud;
 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag;
 - (RVPage *) pageForPackage:(NSString *)name;
 - (void) openMailToURL:(NSURL *)url;
@@ -854,8 +1033,8 @@ class Progress :
 
   protected:
     virtual void Update() {
-        [delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
-        [delegate_ setProgressPercent:(Percent / 100)];
+        /*[delegate_ setProgressTitle:[NSString stringWithUTF8String:Op.c_str()]];
+        [delegate_ setProgressPercent:(Percent / 100)];*/
     }
 
   public:
@@ -869,13 +1048,15 @@ class Progress :
     }
 
     virtual void Done() {
-        [delegate_ setProgressPercent:1];
+        //[delegate_ setProgressPercent:1];
     }
 };
 /* }}} */
 
 /* Database Interface {{{ */
 @interface Database : NSObject {
+    unsigned era_;
+
     pkgCacheFile cache_;
     pkgDepCache::Policy *policy_;
     pkgRecords *records_;
@@ -898,6 +1079,7 @@ class Progress :
 }
 
 + (Database *) sharedInstance;
+- (unsigned) era;
 
 - (void) _readCydia:(NSNumber *)fd;
 - (void) _readStatus:(NSNumber *)fd;
@@ -912,6 +1094,7 @@ class Progress :
 - (pkgRecords *) records;
 - (pkgProblemResolver *) resolver;
 - (pkgAcquire &) fetcher;
+- (pkgSourceList &) list;
 - (NSArray *) packages;
 - (NSArray *) sources;
 - (void) reloadData;
@@ -934,6 +1117,7 @@ class Progress :
     NSString *description_;
     NSString *label_;
     NSString *origin_;
+    NSString *support_;
 
     NSString *uri_;
     NSString *distribution_;
@@ -950,6 +1134,8 @@ class Progress :
 
 - (NSComparisonResult) compareByNameAndType:(Source *)source;
 
+- (NSString *) supportForPackage:(NSString *)package;
+
 - (NSDictionary *) record;
 - (BOOL) trusted;
 
@@ -971,24 +1157,27 @@ class Progress :
 
 @implementation Source
 
-- (void) dealloc {
-    [uri_ release];
-    [distribution_ release];
-    [type_ release];
+#define _clear(field) \
+    if (field != nil) \
+        [field release]; \
+    field = nil;
 
-    if (description_ != nil)
-        [description_ release];
-    if (label_ != nil)
-        [label_ release];
-    if (origin_ != nil)
-        [origin_ release];
-    if (version_ != nil)
-        [version_ release];
-    if (defaultIcon_ != nil)
-        [defaultIcon_ release];
-    if (record_ != nil)
-        [record_ release];
+- (void) _clear {
+    _clear(uri_)
+    _clear(distribution_)
+    _clear(type_)
+
+    _clear(description_)
+    _clear(label_)
+    _clear(origin_)
+    _clear(support_)
+    _clear(version_)
+    _clear(defaultIcon_)
+    _clear(record_)
+}
 
+- (void) dealloc {
+    [self _clear];
     [super dealloc];
 }
 
@@ -1004,44 +1193,52 @@ class Progress :
     return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name];
 }
 
-- (Source *) initWithMetaIndex:(metaIndex *)index {
-    if ((self = [super init]) != nil) {
-        trusted_ = index->IsTrusted();
-
-        uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
-        distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
-        type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
-
-        debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
-        if (dindex != NULL) {
-            std::ifstream release(dindex->MetaIndexFile("Release").c_str());
-            std::string line;
-            while (std::getline(release, line)) {
-                std::string::size_type colon(line.find(':'));
-                if (colon == std::string::npos)
-                    continue;
+- (void) setMetaIndex:(metaIndex *)index {
+    [self _clear];
 
-                std::string name(line.substr(0, colon));
-                std::string value(line.substr(colon + 1));
-                while (!value.empty() && value[0] == ' ')
-                    value = value.substr(1);
-
-                if (name == "Default-Icon")
-                    defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
-                else if (name == "Description")
-                    description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
-                else if (name == "Label")
-                    label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
-                else if (name == "Origin")
-                    origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
-                else if (name == "Version")
-                    version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
-            }
+    trusted_ = index->IsTrusted();
+
+    uri_ = [[NSString stringWithUTF8String:index->GetURI().c_str()] retain];
+    distribution_ = [[NSString stringWithUTF8String:index->GetDist().c_str()] retain];
+    type_ = [[NSString stringWithUTF8String:index->GetType()] retain];
+
+    debReleaseIndex *dindex(dynamic_cast<debReleaseIndex *>(index));
+    if (dindex != NULL) {
+        std::ifstream release(dindex->MetaIndexFile("Release").c_str());
+        std::string line;
+        while (std::getline(release, line)) {
+            std::string::size_type colon(line.find(':'));
+            if (colon == std::string::npos)
+                continue;
+
+            std::string name(line.substr(0, colon));
+            std::string value(line.substr(colon + 1));
+            while (!value.empty() && value[0] == ' ')
+                value = value.substr(1);
+
+            if (name == "Default-Icon")
+                defaultIcon_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+            else if (name == "Description")
+                description_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+            else if (name == "Label")
+                label_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+            else if (name == "Origin")
+                origin_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+            else if (name == "Support")
+                support_ = [[NSString stringWithUTF8String:value.c_str()] retain];
+            else if (name == "Version")
+                version_ = [[NSString stringWithUTF8String:value.c_str()] retain];
         }
+    }
 
-        record_ = [Sources_ objectForKey:[self key]];
-        if (record_ != nil)
-            record_ = [record_ retain];
+    record_ = [Sources_ objectForKey:[self key]];
+    if (record_ != nil)
+        record_ = [record_ retain];
+}
+
+- (Source *) initWithMetaIndex:(metaIndex *)index {
+    if ((self = [super init]) != nil) {
+        [self setMetaIndex:index];
     } return self;
 }
 
@@ -1068,6 +1265,10 @@ class Progress :
     return [lhs compare:rhs options:LaxCompareOptions_];
 }
 
+- (NSString *) supportForPackage:(NSString *)package {
+    return support_ == nil ? nil : [support_ stringByReplacingOccurrencesOfString:@"*" withString:package];
+}
+
 - (NSDictionary *) record {
     return record_;
 }
@@ -1159,6 +1360,8 @@ class Progress :
 /* }}} */
 /* Package Class {{{ */
 @interface Package : NSObject {
+    unsigned era_;
+
     pkgCache::PkgIterator iterator_;
     _transient Database *database_;
     pkgCache::VerIterator version_;
@@ -1168,6 +1371,7 @@ class Progress :
     bool cached_;
 
     NSString *section_;
+    bool essential_;
 
     NSString *latest_;
     NSString *installed_;
@@ -1180,6 +1384,7 @@ class Progress :
     NSString *homepage_;
     Address *sponsor_;
     Address *author_;
+    NSString *support_;
     NSArray *tags_;
     NSString *role_;
 
@@ -1194,10 +1399,12 @@ class Progress :
 - (NSString *) section;
 - (NSString *) simpleSection;
 
+- (NSString *) uri;
+
 - (Address *) maintainer;
 - (size_t) size;
 - (NSString *) description;
-- (NSString *) index;
+- (unichar) index;
 
 - (NSMutableDictionary *) metadata;
 - (NSDate *) seen;
@@ -1228,6 +1435,8 @@ class Progress :
 - (NSString *) depiction;
 - (Address *) author;
 
+- (NSString *) support;
+
 - (NSArray *) files;
 - (NSArray *) relationships;
 - (NSArray *) warnings;
@@ -1235,7 +1444,6 @@ class Progress :
 
 - (Source *) source;
 - (NSString *) role;
-- (NSString *) rating;
 
 - (BOOL) matches:(NSString *)text;
 
@@ -1243,6 +1451,7 @@ class Progress :
 - (BOOL) hasTag:(NSString *)tag;
 - (NSString *) primaryPurpose;
 - (NSArray *) purposes;
+- (bool) isCommercial;
 
 - (NSComparisonResult) compareByName:(Package *)package;
 - (NSComparisonResult) compareBySection:(Package *)package;
@@ -1252,10 +1461,10 @@ class Progress :
 - (void) install;
 - (void) remove;
 
-- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search;
-- (NSNumber *) isInstalledAndVisible:(NSNumber *)number;
-- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)section;
-- (NSNumber *) isVisibleInSource:(Source *)source;
+- (bool) isUnfilteredAndSearchedForBy:(NSString *)search;
+- (bool) isInstalledAndVisible:(NSNumber *)number;
+- (bool) isVisiblyUninstalledInSection:(NSString *)section;
+- (bool) isVisibleInSource:(Source *)source;
 
 @end
 
@@ -1264,7 +1473,6 @@ class Progress :
 - (void) dealloc {
     if (source_ != nil)
         [source_ release];
-
     if (section_ != nil)
         [section_ release];
 
@@ -1286,6 +1494,8 @@ class Progress :
         [sponsor_ release];
     if (author_ != nil)
         [author_ release];
+    if (support_ != nil)
+        [support_ release];
     if (tags_ != nil)
         [tags_ release];
     if (role_ != nil)
@@ -1297,8 +1507,19 @@ class Progress :
     [super dealloc];
 }
 
++ (NSString *) webScriptNameForSelector:(SEL)selector {
+    if (selector == @selector(hasTag:))
+        return @"hasTag";
+    else
+        return nil;
+}
+
++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector {
+    return [self webScriptNameForSelector:selector] == nil;
+}
+
 + (NSArray *) _attributeKeys {
-    return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"rating", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil];
+    return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"mode", @"name", @"purposes", @"section", @"size", @"source", @"sponsor", @"support", @"tagline", @"warnings", nil];
 }
 
 - (NSArray *) attributeKeys {
@@ -1311,156 +1532,216 @@ class Progress :
 
 - (Package *) initWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
     if ((self = [super init]) != nil) {
+    _profile(Package$initWithIterator)
+    @synchronized (database) {
+        era_ = [database era];
+
         iterator_ = iterator;
         database_ = database;
 
-        version_ = [database_ policy]->GetCandidateVer(iterator_);
+        _profile(Package$initWithIterator$Control)
+        _end
+
+        _profile(Package$initWithIterator$Version)
+            version_ = [database_ policy]->GetCandidateVer(iterator_);
+        _end
+
         NSString *latest = version_.end() ? nil : [NSString stringWithUTF8String:version_.VerStr()];
-        latest_ = latest == nil ? nil : [StripVersion(latest) retain];
 
-        pkgCache::VerIterator current = iterator_.CurrentVer();
-        NSString *installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()];
-        installed_ = [StripVersion(installed) retain];
+        _profile(Package$initWithIterator$Latest)
+            latest_ = latest == nil ? nil : [StripVersion(latest) retain];
+        _end
 
-        if (!version_.end())
-            file_ = version_.FileList();
-        else {
-            pkgCache &cache([database_ cache]);
-            file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
-        }
+        pkgCache::VerIterator current;
+        NSString *installed;
 
-        id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain];
-
-        if (!file_.end()) {
-            pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
-
-            const char *begin, *end;
-            parser->GetRec(begin, end);
-
-            NSString *website(nil);
-            NSString *sponsor(nil);
-            NSString *author(nil);
-            NSString *tag(nil);
-
-            struct {
-                const char *name_;
-                NSString **value_;
-            } names[] = {
-                {"name", &name_},
-                {"icon", &icon_},
-                {"depiction", &depiction_},
-                {"homepage", &homepage_},
-                {"website", &website},
-                {"sponsor", &sponsor},
-                {"author", &author},
-                {"tag", &tag},
-            };
-
-            while (begin != end)
-                if (*begin == '\n') {
-                    ++begin;
-                    continue;
-                } else if (isblank(*begin)) next: {
-                    begin = static_cast<char *>(memchr(begin + 1, '\n', end - begin - 1));
-                    if (begin == NULL)
-                        break;
-                } else if (const char *colon = static_cast<char *>(memchr(begin, ':', end - begin))) {
-                    const char *name(begin);
-                    size_t size(colon - begin);
-
-                    begin = static_cast<char *>(memchr(begin, '\n', end - begin));
-
-                    {
-                        const char *stop(begin == NULL ? end : begin);
-                        while (stop[-1] == '\r')
-                            --stop;
-                        while (++colon != stop && isblank(*colon));
-
-                        for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i)
-                            if (strncasecmp(names[i].name_, name, size) == 0) {
-                                NSString *value([NSString stringWithUTF8Bytes:colon length:(stop - colon)]);
-                                *names[i].value_ = value;
-                                break;
-                            }
-                    }
+        _profile(Package$initWithIterator$Current)
+            current = iterator_.CurrentVer();
+            installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()];
+        _end
 
-                    if (begin == NULL)
-                        break;
-                    ++begin;
-                } else goto next;
-
-            if (name_ != nil)
-                name_ = [name_ retain];
-            tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
-            if (icon_ != nil)
-                icon_ = [icon_ retain];
-            if (depiction_ != nil)
-                depiction_ = [depiction_ retain];
-            if (homepage_ == nil)
-                homepage_ = website;
-            if ([homepage_ isEqualToString:depiction_])
-                homepage_ = nil;
-            if (homepage_ != nil)
-                homepage_ = [homepage_ retain];
-            if (sponsor != nil)
-                sponsor_ = [[Address addressWithString:sponsor] retain];
-            if (author != nil)
-                author_ = [[Address addressWithString:author] retain];
-            if (tag != nil)
-                tags_ = [[tag componentsSeparatedByString:@", "] retain];
-        }
+        _profile(Package$initWithIterator$Installed)
+            installed_ = [StripVersion(installed) retain];
+        _end
 
-        if (tags_ != nil)
-            for (int i(0), e([tags_ count]); i != e; ++i) {
-                NSString *tag = [tags_ objectAtIndex:i];
-                if ([tag hasPrefix:@"role::"]) {
-                    role_ = [[tag substringFromIndex:6] retain];
-                    break;
-                }
+        _profile(Package$initWithIterator$File)
+            if (!version_.end())
+                file_ = version_.FileList();
+            else {
+                pkgCache &cache([database_ cache]);
+                file_ = pkgCache::VerFileIterator(cache, cache.VerFileP);
             }
+        _end
+
+        _profile(Package$initWithIterator$Name)
+            id_ = [[NSString stringWithUTF8String:iterator_.Name()] retain];
+        _end
+
+        if (!file_.end())
+            _profile(Package$initWithIterator$Parse)
+                pkgRecords::Parser *parser;
+
+                _profile(Package$initWithIterator$Parse$Lookup)
+                    parser = &[database_ records]->Lookup(file_);
+                _end
+
+                const char *begin, *end;
+                parser->GetRec(begin, end);
+
+                NSString *website(nil);
+                NSString *sponsor(nil);
+                NSString *author(nil);
+                NSString *tag(nil);
+
+                struct {
+                    const char *name_;
+                    NSString **value_;
+                } names[] = {
+                    {"name", &name_},
+                    {"icon", &icon_},
+                    {"depiction", &depiction_},
+                    {"homepage", &homepage_},
+                    {"website", &website},
+                    {"support", &support_},
+                    {"sponsor", &sponsor},
+                    {"author", &author},
+                    {"tag", &tag},
+                };
+
+                while (begin != end)
+                    if (*begin == '\n') {
+                        ++begin;
+                        continue;
+                    } else if (isblank(*begin)) next: {
+                        begin = static_cast<char *>(memchr(begin + 1, '\n', end - begin - 1));
+                        if (begin == NULL)
+                            break;
+                    } else if (const char *colon = static_cast<char *>(memchr(begin, ':', end - begin))) {
+                        const char *name(begin);
+                        size_t size(colon - begin);
+
+                        begin = static_cast<char *>(memchr(begin, '\n', end - begin));
+
+                        {
+                            const char *stop(begin == NULL ? end : begin);
+                            while (stop[-1] == '\r')
+                                --stop;
+                            while (++colon != stop && isblank(*colon));
+
+                            for (size_t i(0); i != sizeof(names) / sizeof(names[0]); ++i)
+                                if (strncasecmp(names[i].name_, name, size) == 0) {
+                                    NSString *value;
+
+                                    _profile(Package$initWithIterator$Parse$Value)
+                                        value = [NSString stringWithUTF8Bytes:colon length:(stop - colon)];
+                                    _end
+
+                                    *names[i].value_ = value;
+                                    break;
+                                }
+                        }
+
+                        if (begin == NULL)
+                            break;
+                        ++begin;
+                    } else goto next;
+
+                _profile(Package$initWithIterator$Parse$Retain)
+                    if (name_ != nil)
+                        name_ = [name_ retain];
+                    _profile(Package$initWithIterator$Parse$Tagline)
+                        tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
+                    _end
+                    if (icon_ != nil)
+                        icon_ = [icon_ retain];
+                    if (depiction_ != nil)
+                        depiction_ = [depiction_ retain];
+                    if (homepage_ == nil)
+                        homepage_ = website;
+                    if ([homepage_ isEqualToString:depiction_])
+                        homepage_ = nil;
+                    if (homepage_ != nil)
+                        homepage_ = [homepage_ retain];
+                    if (sponsor != nil)
+                        sponsor_ = [[Address addressWithString:sponsor] retain];
+                    if (author != nil)
+                        author_ = [[Address addressWithString:author] retain];
+                    if (tag != nil)
+                        tags_ = [[tag componentsSeparatedByString:@", "] retain];
+                _end
+            _end
+
+        _profile(Package$initWithIterator$Tags)
+            if (tags_ != nil)
+                for (NSString *tag in tags_)
+                    if ([tag hasPrefix:@"role::"]) {
+                        role_ = [[tag substringFromIndex:6] retain];
+                        break;
+                    }
+        _end
 
         NSString *solid(latest == nil ? installed : latest);
         bool changed(false);
 
         NSString *key([id_ lowercaseString]);
 
-        NSMutableDictionary *metadata = [Packages_ objectForKey:key];
-        if (metadata == nil) {
-            metadata = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
-                now_, @"FirstSeen",
-            nil] mutableCopy];
-
-            if (solid != nil)
-                [metadata setObject:solid forKey:@"LastVersion"];
-            changed = true;
-        } else {
-            NSDate *first([metadata objectForKey:@"FirstSeen"]);
-            NSDate *last([metadata objectForKey:@"LastSeen"]);
-            NSString *version([metadata objectForKey:@"LastVersion"]);
+        _profile(Package$initWithIterator$Metadata)
+            NSMutableDictionary *metadata = [Packages_ objectForKey:key];
+            if (metadata == nil) {
+                metadata = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
+                    now_, @"FirstSeen",
+                nil] mutableCopy];
 
-            if (first == nil) {
-                first = last == nil ? now_ : last;
-                [metadata setObject:first forKey:@"FirstSeen"];
+                if (solid != nil)
+                    [metadata setObject:solid forKey:@"LastVersion"];
                 changed = true;
+            } else {
+                NSDate *first([metadata objectForKey:@"FirstSeen"]);
+                NSDate *last([metadata objectForKey:@"LastSeen"]);
+                NSString *version([metadata objectForKey:@"LastVersion"]);
+
+                if (first == nil) {
+                    first = last == nil ? now_ : last;
+                    [metadata setObject:first forKey:@"FirstSeen"];
+                    changed = true;
+                }
+
+                if (solid != nil)
+                    if (version == nil) {
+                        [metadata setObject:solid forKey:@"LastVersion"];
+                        changed = true;
+                    } else if (![version isEqualToString:solid]) {
+                        [metadata setObject:solid forKey:@"LastVersion"];
+                        last = now_;
+                        [metadata setObject:last forKey:@"LastSeen"];
+                        changed = true;
+                    }
             }
 
-            if (solid != nil)
-                if (version == nil) {
-                    [metadata setObject:solid forKey:@"LastVersion"];
-                    changed = true;
-                } else if (![version isEqualToString:solid]) {
-                    [metadata setObject:solid forKey:@"LastVersion"];
-                    last = now_;
-                    [metadata setObject:last forKey:@"LastSeen"];
-                    changed = true;
+            if (changed) {
+                [Packages_ setObject:metadata forKey:key];
+                Changed_ = true;
+            }
+        _end
+
+        const char *section(iterator_.Section());
+        if (section == NULL)
+            section_ = nil;
+        else {
+            NSString *name([[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_']);
+
+          lookup:
+            if (NSDictionary *value = [SectionMap_ objectForKey:name])
+                if (NSString *rename = [value objectForKey:@"Rename"]) {
+                    name = rename;
+                    goto lookup;
                 }
-        }
 
-        if (changed) {
-            [Packages_ setObject:metadata forKey:key];
-            Changed_ = true;
+            section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain];
         }
-    } return self;
+
+        essential_ = (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
+    } _end } return self;
 }
 
 + (Package *) packageWithIterator:(pkgCache::PkgIterator)iterator database:(Database *)database {
@@ -1475,23 +1756,6 @@ class Progress :
 }
 
 - (NSString *) section {
-    if (section_ != nil)
-        return section_;
-
-    const char *section = iterator_.Section();
-    if (section == NULL)
-        return nil;
-
-    NSString *name = [[NSString stringWithUTF8String:section] stringByReplacingCharacter:' ' withCharacter:'_'];
-
-  lookup:
-    if (NSDictionary *value = [SectionMap_ objectForKey:name])
-        if (NSString *rename = [value objectForKey:@"Rename"]) {
-            name = rename;
-            goto lookup;
-        }
-
-    section_ = [[name stringByReplacingCharacter:'_' withCharacter:' '] retain];
     return section_;
 }
 
@@ -1500,14 +1764,27 @@ class Progress :
         return Simplify(section);
     else
         return nil;
+}
 
+- (NSString *) uri {
+    return nil;
+#if 0
+    pkgIndexFile *index;
+    pkgCache::PkgFileIterator file(file_.File());
+    if (![database_ list].FindIndex(file, index))
+        return nil;
+    return [NSString stringWithUTF8String:iterator_->Path];
+    //return [NSString stringWithUTF8String:file.Site()];
+    //return [NSString stringWithUTF8String:index->ArchiveURI(file.FileName()).c_str()];
+#endif
 }
 
 - (Address *) maintainer {
     if (file_.end())
         return nil;
     pkgRecords::Parser *parser = &[database_ records]->Lookup(file_);
-    return [Address addressWithString:[NSString stringWithUTF8String:parser->Maintainer().c_str()]];
+    const std::string &maintainer(parser->Maintainer());
+    return maintainer.empty() ? nil : [Address addressWithString:[NSString stringWithUTF8String:maintainer.c_str()]];
 }
 
 - (size_t) size {
@@ -1526,7 +1803,7 @@ class Progress :
         return nil;
 
     NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
-    for (size_t i(1); i != [lines count]; ++i) {
+    for (size_t i(1), e([lines count]); i != e; ++i) {
         NSString *trim = [[lines objectAtIndex:i] stringByTrimmingCharactersInSet:whitespace];
         [trimmed addObject:trim];
     }
@@ -1534,9 +1811,16 @@ class Progress :
     return [trimmed componentsJoinedByString:@"\n"];
 }
 
-- (NSString *) index {
-    NSString *index = [[[self name] substringToIndex:1] uppercaseString];
-    return [index length] != 0 && isalpha([index characterAtIndex:0]) ? index : @"123";
+- (unichar) index {
+    _profile(Package$index)
+        NSString *name([self name]);
+        if ([name length] == 0)
+            return '#';
+        unichar character([name characterAtIndex:0]);
+        if (!isalpha(character))
+            return '#';
+        return toupper(character);
+    _end
 }
 
 - (NSMutableDictionary *) metadata {
@@ -1582,14 +1866,16 @@ class Progress :
 - (BOOL) upgradableAndEssential:(BOOL)essential {
     pkgCache::VerIterator current = iterator_.CurrentVer();
 
+    bool value;
     if (current.end())
-        return essential && [self essential];
+        value = essential && [self essential] && [self visible];
     else
-        return !version_.end() && version_ != current;
+        value = !version_.end() && version_ != current;// && (!essential || ![database_ cache][iterator_].Keep());
+    return value;
 }
 
 - (BOOL) essential {
-    return (iterator_->Flags & pkgCache::Flag::Essential) == 0 ? NO : YES;
+    return essential_;
 }
 
 - (BOOL) broken {
@@ -1633,14 +1919,16 @@ class Progress :
             else
                 return @"Remove";
         case pkgDepCache::ModeKeep:
-            if ((state.iFlags & pkgDepCache::AutoKept) != 0)
-                return nil;
+            if ((state.iFlags & pkgDepCache::ReInstall) != 0)
+                return @"Reinstall";
+            /*else if ((state.iFlags & pkgDepCache::AutoKept) != 0)
+                return nil;*/
             else
                 return nil;
         case pkgDepCache::ModeInstall:
-            if ((state.iFlags & pkgDepCache::ReInstall) != 0)
+            /*if ((state.iFlags & pkgDepCache::ReInstall) != 0)
                 return @"Reinstall";
-            else switch (state.Status) {
+            else*/ switch (state.Status) {
                 case -1:
                     return @"Downgrade";
                 case 0:
@@ -1673,12 +1961,14 @@ class Progress :
     NSString *section = [self simpleSection];
 
     UIImage *icon(nil);
-    if (NSString *icon = icon_)
-        icon = [UIImage imageAtPath:[icon_ substringFromIndex:6]];
+    if (icon_ != nil)
+        if ([icon_ hasPrefix:@"file:///"])
+            icon = [UIImage imageAtPath:[icon_ substringFromIndex:7]];
     if (icon == nil) if (section != nil)
         icon = [UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]];
-    if (icon == nil) if (source_ != nil) if (NSString *icon = [source_ defaultIcon])
-        icon = [UIImage imageAtPath:[icon substringFromIndex:6]];
+    if (icon == nil) if (source_ != nil) if (NSString *dicon = [source_ defaultIcon])
+        if ([dicon hasPrefix:@"file:///"])
+            icon = [UIImage imageAtPath:[dicon substringFromIndex:7]];
     if (icon == nil)
         icon = [UIImage applicationImageNamed:@"unknown.png"];
     return icon;
@@ -1700,6 +1990,10 @@ class Progress :
     return author_;
 }
 
+- (NSString *) support {
+    return support_ != nil ? support_ : [[self source] supportForPackage:id_];
+}
+
 - (NSArray *) files {
     NSString *path = [NSString stringWithFormat:@"/var/lib/dpkg/info/%@.list", id_];
     NSMutableArray *files = [NSMutableArray arrayWithCapacity:128];
@@ -1801,8 +2095,17 @@ class Progress :
 
 - (Source *) source {
     if (!cached_) {
-        source_ = file_.end() ? nil : [[database_ getSource:file_.File()] retain];
-        cached_ = true;
+        @synchronized (database_) {
+            if ([database_ era] != era_ || file_.end())
+                source_ = nil;
+            else {
+                source_ = [database_ getSource:file_.File()];
+                if (source_ != nil)
+                    [source_ retain];
+            }
+
+            cached_ = true;
+        }
     }
 
     return source_;
@@ -1812,28 +2115,21 @@ class Progress :
     return role_;
 }
 
-- (NSString *) rating {
-    if (NSString *rating = [Indices_ objectForKey:@"Rating"])
-        return [rating stringByReplacingOccurrencesOfString:@"@P" withString:[id_ stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
-    else
-        return nil;
-}
-
 - (BOOL) matches:(NSString *)text {
     if (text == nil)
         return NO;
 
     NSRange range;
 
-    range = [[self id] rangeOfString:text options:NSCaseInsensitiveSearch];
+    range = [[self id] rangeOfString:text options:MatchCompareOptions_];
     if (range.location != NSNotFound)
         return YES;
 
-    range = [[self name] rangeOfString:text options:NSCaseInsensitiveSearch];
+    range = [[self name] rangeOfString:text options:MatchCompareOptions_];
     if (range.location != NSNotFound)
         return YES;
 
-    range = [[self tagline] rangeOfString:text options:NSCaseInsensitiveSearch];
+    range = [[self tagline] rangeOfString:text options:MatchCompareOptions_];
     if (range.location != NSNotFound)
         return YES;
 
@@ -1877,6 +2173,10 @@ class Progress :
     return [purposes count] == 0 ? nil : purposes;
 }
 
+- (bool) isCommercial {
+    return [self hasTag:@"cydia::commercial"];
+}
+
 - (NSComparisonResult) compareByName:(Package *)package {
     NSString *lhs = [self name];
     NSString *rhs = [package name];
@@ -1921,9 +2221,10 @@ class Progress :
         } bits;
     } value;
 
-    value.bits.upgradable = [self upgradableAndEssential:YES] ? 1 : 0;
+    bool upgradable([self upgradableAndEssential:YES]);
+    value.bits.upgradable = upgradable ? 1 : 0;
 
-    if ([self upgradableAndEssential:YES]) {
+    if (upgradable) {
         value.bits.timestamp = 0;
         value.bits.ignored = [self ignored] ? 0 : 1;
         value.bits.upgradable = 1;
@@ -1936,6 +2237,12 @@ class Progress :
     return _not(uint32_t) - value.key;
 }
 
+- (void) clear {
+    pkgProblemResolver *resolver = [database_ resolver];
+    resolver->Clear(iterator_);
+    resolver->Protect(iterator_);
+}
+
 - (void) install {
     pkgProblemResolver *resolver = [database_ resolver];
     resolver->Clear(iterator_);
@@ -1955,33 +2262,40 @@ class Progress :
     [database_ cache]->MarkDelete(iterator_, true);
 }
 
-- (NSNumber *) isUnfilteredAndSearchedForBy:(NSString *)search {
-    return [NSNumber numberWithBool:(
-        [self unfiltered] && [self matches:search]
-    )];
+- (bool) isUnfilteredAndSearchedForBy:(NSString *)search {
+    _profile(Package$isUnfilteredAndSearchedForBy)
+        bool value(true);
+
+        _profile(Package$isUnfilteredAndSearchedForBy$Unfiltered)
+            value &= [self unfiltered];
+        _end
+
+        _profile(Package$isUnfilteredAndSearchedForBy$Match)
+            value &= [self matches:search];
+        _end
+
+        return value;
+    _end
 }
 
-- (NSNumber *) isInstalledAndVisible:(NSNumber *)number {
-    return [NSNumber numberWithBool:(
-        (![number boolValue] || [self visible]) && [self installed] != nil
-    )];
+- (bool) isInstalledAndVisible:(NSNumber *)number {
+    return (![number boolValue] || [self visible]) && [self installed] != nil;
 }
 
-- (NSNumber *) isVisiblyUninstalledInSection:(NSString *)name {
+- (bool) isVisiblyUninstalledInSection:(NSString *)name {
     NSString *section = [self section];
 
-    return [NSNumber numberWithBool:(
+    return
         [self visible] &&
         [self installed] == nil && (
             name == nil ||
             section == nil && [name length] == 0 ||
             [name isEqualToString:section]
-        )
-    )];
+        );
 }
 
-- (NSNumber *) isVisibleInSource:(Source *)source {
-    return [NSNumber numberWithBool:([self source] == source && [self visible])];
+- (bool) isVisibleInSource:(Source *)source {
+    return [self source] == source && [self visible];
 }
 
 @end
@@ -1989,6 +2303,7 @@ class Progress :
 /* Section Class {{{ */
 @interface Section : NSObject {
     NSString *name_;
+    unichar index_;
     size_t row_;
     size_t count_;
 }
@@ -1996,7 +2311,9 @@ class Progress :
 - (NSComparisonResult) compareByName:(Section *)section;
 - (Section *) initWithName:(NSString *)name;
 - (Section *) initWithName:(NSString *)name row:(size_t)row;
+- (Section *) initWithIndex:(unichar)index row:(size_t)row;
 - (NSString *) name;
+- (unichar) index;
 - (size_t) row;
 - (size_t) count;
 - (void) addToCount;
@@ -2034,6 +2351,15 @@ class Progress :
 - (Section *) initWithName:(NSString *)name row:(size_t)row {
     if ((self = [super init]) != nil) {
         name_ = [name retain];
+        index_ = '\0';
+        row_ = row;
+    } return self;
+}
+
+- (Section *) initWithIndex:(unichar)index row:(size_t)row {
+    if ((self = [super init]) != nil) {
+        name_ = [(index == '#' ? @"123" : [NSString stringWithCharacters:&index length:1]) retain];
+        index_ = index;
         row_ = row;
     } return self;
 }
@@ -2042,6 +2368,10 @@ class Progress :
     return name_;
 }
 
+- (unichar) index {
+    return index_;
+}
+
 - (size_t) row {
     return row_;
 }
@@ -2070,6 +2400,10 @@ static NSArray *Finishes_;
     return instance;
 }
 
+- (unsigned) era {
+    return era_;
+}
+
 - (void) dealloc {
     _assert(false);
     [super dealloc];
@@ -2237,6 +2571,10 @@ static NSArray *Finishes_;
     return *fetcher_;
 }
 
+- (pkgSourceList &) list {
+    return *list_;
+}
+
 - (NSArray *) packages {
     return packages_;
 }
@@ -2309,7 +2647,11 @@ static NSArray *Finishes_;
     return issues;
 }
 
-- (void) reloadData {
+- (void) reloadData { _pooled
+    @synchronized (self) {
+        ++era_;
+    }
+
     _error->Discard();
 
     delete list_;
@@ -2381,13 +2723,15 @@ static NSArray *Finishes_;
 
     [packages_ removeAllObjects];
     _trace();
-    profile_ = 0;
     for (pkgCache::PkgIterator iterator = cache_->PkgBegin(); !iterator.end(); ++iterator)
         if (Package *package = [Package packageWithIterator:iterator database:self])
             [packages_ addObject:package];
     _trace();
     [packages_ sortUsingSelector:@selector(compareByName:)];
     _trace();
+
+    _config->Set("Acquire::http::Timeout", 15);
+    _config->Set("Acquire::http::MaxParallel", 4);
 }
 
 - (void) configure {
@@ -2463,7 +2807,9 @@ static NSArray *Finishes_;
         failed = true;
 
         [delegate_ performSelectorOnMainThread:@selector(_setProgressError:)
-            withObject:[NSArray arrayWithObjects:[NSString stringWithUTF8String:error.c_str()], nil]
+            withObject:[NSArray arrayWithObjects:
+                [NSString stringWithUTF8String:error.c_str()],
+            nil]
             waitUntilDone:YES
         ];
     }
@@ -2693,6 +3039,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @protocol ConfirmationViewDelegate
 - (void) cancel;
 - (void) confirm;
+- (void) queue;
 @end
 
 @interface ConfirmationView : BrowserView {
@@ -2773,8 +3120,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         pkgCacheFile &cache([database_ cache]);
         NSArray *packages = [database_ packages];
-        for (size_t i(0), e = [packages count]; i != e; ++i) {
-            Package *package = [packages objectAtIndex:i];
+        for (Package *package in packages) {
             pkgCache::PkgIterator iterator = [package iterator];
             pkgDepCache::StateCache &state(cache[iterator]);
 
@@ -2858,11 +3204,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Cancel";
 }
 
+- (id) rightButtonTitle {
+    return issues_ != nil ? nil : [super rightButtonTitle];
+}
+
 - (id) _rightButtonTitle {
 #if AlwaysReload || IgnoreInstall
-    return @"Reload";
+    return [super _rightButtonTitle];
 #else
-    return issues_ == nil ? @"Confirm" : nil;
+    return @"Confirm";
 #endif
 }
 
@@ -2946,8 +3296,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     SHA1SumValue springlist_;
     SHA1SumValue notifyconf_;
     SHA1SumValue sandplate_;
-    size_t received_;
-    NSTimeInterval last_;
 }
 
 - (void) transitionViewDidComplete:(UITransitionView*)view fromView:(UIView*)from toView:(UIView*)to;
@@ -3047,6 +3395,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         [status_ setCentersHorizontally:YES];
         //[status_ setFont:font];
+        _trace();
 
         output_ = [[UITextView alloc] initWithFrame:CGRectMake(
             10,
@@ -3054,6 +3403,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             bounds.size.width - 20,
             bounds.size.height - navsize.height - 62 - navrect.size.height
         )];
+        _trace();
 
         //[output_ setTextFont:@"Courier New"];
         [output_ setTextSize:12];
@@ -3099,7 +3449,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
     NSString *context([sheet context]);
 
-    if ([context isEqualToString:@"conffile"]) {
+    if ([context isEqualToString:@"error"])
+        [sheet dismiss];
+    else if ([context isEqualToString:@"conffile"]) {
         FILE *input = [database_ input];
 
         switch (button) {
@@ -3255,9 +3607,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [output_ setText:@""];
     [progress_ setProgress:0];
 
-    received_ = 0;
-    last_ = 0;//[NSDate timeIntervalSinceReferenceDate];
-
     [close_ removeFromSuperview];
     [overlay_ addSubview:progress_];
     [overlay_ addSubview:status_];
@@ -3351,7 +3700,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) startProgress {
-    last_ = [NSDate timeIntervalSinceReferenceDate];
 }
 
 - (void) addProgressOutput:(NSString *)output {
@@ -3363,15 +3711,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (bool) isCancelling:(size_t)received {
-    if (last_ != 0) {
-        NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
-        if (received_ != received) {
-            received_ = received;
-            last_ = now;
-        } else if (now - last_ > 30)
-            return true;
-    }
-
     return false;
 }
 
@@ -3432,12 +3771,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 /* }}} */
 
 /* Package Cell {{{ */
-@interface PackageCell : UISimpleTableCell {
+@interface PackageCell : UITableCell {
     UIImage *icon_;
     NSString *name_;
     NSString *description_;
+    bool commercial_;
     NSString *source_;
     UIImage *badge_;
+    bool cached_;
+    Package *package_;
 #ifdef USE_BADGES
     UITextLabel *status_;
 #endif
@@ -3477,6 +3819,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [badge_ release];
         badge_ = nil;
     }
+
+    [package_ release];
+    package_ = nil;
 }
 
 - (void) dealloc {
@@ -3507,6 +3852,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     name_ = [[package name] retain];
     description_ = [[package tagline] retain];
+    commercial_ = [package isCommercial];
+
+    package_ = [package retain];
 
     NSString *label = nil;
     bool trusted = false;
@@ -3547,6 +3895,37 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [status_ setText:nil];
     }
 #endif
+
+    cached_ = false;
+}
+
+- (void) drawRect:(CGRect)rect {
+    if (!cached_) {
+        UIColor *color;
+
+        if (NSString *mode = [package_ mode]) {
+            bool remove([mode isEqualToString:@"Remove"] || [mode isEqualToString:@"Purge"]);
+            color = remove ? RemovingColor_ : InstallingColor_;
+        } else
+            color = [UIColor whiteColor];
+
+        [self setBackgroundColor:color];
+        cached_ = true;
+    }
+
+    [super drawRect:rect];
+}
+
+- (void) drawBackgroundInRect:(CGRect)rect withFade:(float)fade {
+    if (fade == 0) {
+        CGContextRef context(UIGraphicsGetCurrentContext());
+        [[self backgroundColor] set];
+        CGRect back(rect);
+        back.size.height -= 1;
+        CGContextFillRect(context, back);
+    }
+
+    [super drawBackgroundInRect:rect withFade:fade];
 }
 
 - (void) drawContentInRect:(CGRect)rect selected:(BOOL)selected {
@@ -3576,17 +3955,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         UISetColor(White_);
 
     if (!selected)
-        UISetColor(Black_);
+        UISetColor(commercial_ ? Purple_ : Black_);
     [name_ drawAtPoint:CGPointMake(48, 8) forWidth:240 withFont:Font18Bold_ ellipsis:2];
     [source_ drawAtPoint:CGPointMake(58, 29) forWidth:225 withFont:Font12_ ellipsis:2];
 
     if (!selected)
-        UISetColor(Gray_);
+        UISetColor(commercial_ ? Purplish_ : Gray_);
     [description_ drawAtPoint:CGPointMake(12, 46) forWidth:280 withFont:Font14_ ellipsis:2];
 
     [super drawContentInRect:rect selected:selected];
 }
 
+- (void) setSelected:(BOOL)selected withFade:(BOOL)fade {
+    cached_ = false;
+    [super setSelected:selected withFade:fade];
+}
+
 + (int) heightForPackage:(Package *)package {
     NSString *tagline([package tagline]);
     int height = tagline == nil || [tagline length] == 0 ? -17 : 0;
@@ -3849,6 +4233,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     _transient Database *database_;
     Package *package_;
     NSString *name_;
+    bool commercial_;
     NSMutableArray *buttons_;
 }
 
@@ -3869,7 +4254,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) _clickButtonWithName:(NSString *)name {
-    if ([name isEqualToString:@"Install"])
+    if ([name isEqualToString:@"Clear"])
+        [delegate_ clearPackage:package_];
+    else if ([name isEqualToString:@"Install"])
         [delegate_ installPackage:package_];
     else if ([name isEqualToString:@"Reinstall"])
         [delegate_ installPackage:package_];
@@ -3905,11 +4292,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [super webView:sender didClearWindowObject:window forFrame:frame];
 }
 
-#if !AlwaysReload
-- (void) _rightButtonClicked {
-    /*[super _rightButtonClicked];
-    return;*/
+- (bool) _allowJavaScriptPanel {
+    return commercial_;
+}
 
+#if !AlwaysReload
+- (void) __rightButtonClicked {
     int count = [buttons_ count];
     _assert(count != 0);
 
@@ -3923,12 +4311,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [delegate_ slideUp:[[[UIActionSheet alloc]
             initWithTitle:nil
             buttons:buttons
-            defaultButtonIndex:2
+            defaultButtonIndex:([buttons count] - 1)
             delegate:self
             context:@"modify"
         ] autorelease]];
     }
 }
+
+- (void) _rightButtonClicked {
+    if (commercial_)
+        [super _rightButtonClicked];
+    else
+        [self __rightButtonClicked];
+}
 #endif
 
 - (id) _rightButtonTitle {
@@ -3963,9 +4358,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if (package != nil) {
         package_ = [package retain];
         name_ = [[package id] retain];
+        commercial_ = [package isCommercial];
 
         [self loadURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"package" ofType:@"html"]]];
 
+        if ([package_ mode] != nil)
+            [buttons_ addObject:@"Clear"];
         if ([package_ source] == nil);
         else if ([package_ upgradableAndEssential:NO])
             [buttons_ addObject:@"Upgrade"];
@@ -3978,8 +4376,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
-- (bool) _loading {
-    return false;
+- (bool) isLoading {
+    return commercial_ ? [super isLoading] : false;
 }
 
 - (void) reloadData {
@@ -3993,17 +4391,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @interface PackageTable : RVPage {
     _transient Database *database_;
     NSString *title_;
-    SEL filter_;
-    id object_;
     NSMutableArray *packages_;
     NSMutableArray *sections_;
     UISectionList *list_;
 }
 
-- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
+- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title;
 
 - (void) setDelegate:(id)delegate;
-- (void) setObject:(id)object;
 
 - (void) reloadData;
 - (void) resetCursor;
@@ -4020,8 +4415,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [list_ setDataSource:nil];
 
     [title_ release];
-    if (object_ != nil)
-        [object_ release];
     [packages_ release];
     [sections_ release];
     [list_ release];
@@ -4065,18 +4458,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         return;
 
     Package *package = [packages_ objectAtIndex:row];
+    package = [database_ packageWithName:[package id]];
     PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
-    [view setDelegate:delegate_];
     [view setPackage:package];
+    [view setDelegate:delegate_];
     [book_ pushPage:view];
 }
 
-- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
+- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title {
     if ((self = [super initWithBook:book]) != nil) {
         database_ = database;
         title_ = [title retain];
-        filter_ = filter;
-        object_ = object == nil ? nil : [object retain];
 
         packages_ = [[NSMutableArray arrayWithCapacity:16] retain];
         sections_ = [[NSMutableArray arrayWithCapacity:16] retain];
@@ -4097,7 +4489,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [table setReusesTableCells:YES];
 
         [self addSubview:list_];
-        [self reloadData];
 
         [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
         [list_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
@@ -4108,13 +4499,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     delegate_ = delegate;
 }
 
-- (void) setObject:(id)object {
-    if (object_ != nil)
-        [object_ release];
-    if (object == nil)
-        object_ = nil;
-    else
-        object_ = [object retain];
+- (bool) hasPackage:(Package *)package {
+    return true;
 }
 
 - (void) reloadData {
@@ -4123,27 +4509,41 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [packages_ removeAllObjects];
     [sections_ removeAllObjects];
 
-    for (size_t i(0); i != [packages count]; ++i) {
-        Package *package([packages objectAtIndex:i]);
-        if ([package valid] && [[package performSelector:filter_ withObject:object_] boolValue])
-            [packages_ addObject:package];
-    }
+    _profile(PackageTable$reloadData$Filter)
+        for (Package *package in packages)
+            if ([self hasPackage:package])
+                [packages_ addObject:package];
+    _end
 
     Section *section = nil;
 
-    for (size_t offset(0); offset != [packages_ count]; ++offset) {
-        Package *package = [packages_ objectAtIndex:offset];
-        NSString *name = [package index];
+    _profile(PackageTable$reloadData$Section)
+        for (size_t offset(0), end([packages_ count]); offset != end; ++offset) {
+            Package *package;
+            unichar index;
 
-        if (section == nil || ![[section name] isEqualToString:name]) {
-            section = [[[Section alloc] initWithName:name row:offset] autorelease];
-            [sections_ addObject:section];
-        }
+            _profile(PackageTable$reloadData$Section$Package)
+                package = [packages_ objectAtIndex:offset];
+                index = [package index];
+            _end
 
-        [section addToCount];
-    }
+            if (section == nil || [section index] != index) {
+                _profile(PackageTable$reloadData$Section$Allocate)
+                    section = [[[Section alloc] initWithIndex:index row:offset] autorelease];
+                _end
 
-    [list_ reloadData];
+                _profile(PackageTable$reloadData$Section$Add)
+                    [sections_ addObject:section];
+                _end
+            }
+
+            [section addToCount];
+        }
+    _end
+
+    _profile(PackageTable$reloadData$List)
+        [list_ reloadData];
+    _end
 }
 
 - (NSString *) title {
@@ -4166,6 +4566,58 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [list_ setShouldHideHeaderInShortLists:hide];
 }
 
+@end
+/* }}} */
+/* Filtered Package Table {{{ */
+@interface FilteredPackageTable : PackageTable {
+    SEL filter_;
+    IMP imp_;
+    id object_;
+}
+
+- (void) setObject:(id)object;
+
+- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object;
+
+@end
+
+@implementation FilteredPackageTable
+
+- (void) dealloc {
+    if (object_ != nil)
+        [object_ release];
+    [super dealloc];
+}
+
+- (void) setObject:(id)object {
+    if (object_ != nil)
+        [object_ release];
+    if (object == nil)
+        object_ = nil;
+    else
+        object_ = [object retain];
+}
+
+- (bool) hasPackage:(Package *)package {
+    _profile(FilteredPackageTable$hasPackage)
+        return [package valid] && (*reinterpret_cast<bool (*)(id, SEL, id)>(imp_))(package, filter_, object_);
+    _end
+}
+
+- (id) initWithBook:(RVBook *)book database:(Database *)database title:(NSString *)title filter:(SEL)filter with:(id)object {
+    if ((self = [super initWithBook:book database:database title:title]) != nil) {
+        filter_ = filter;
+        object_ = object == nil ? nil : [object retain];
+
+        /* XXX: this is an unsafe optimization of doomy hell */
+        Method method = class_getInstanceMethod([Package class], filter);
+        imp_ = method_getImplementation(method);
+        _assert(imp_ != NULL);
+
+        [self reloadData];
+    } return self;
+}
+
 @end
 /* }}} */
 
@@ -4362,7 +4814,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     Source *source = [sources_ objectAtIndex:row];
 
-    PackageTable *packages = [[[PackageTable alloc]
+    PackageTable *packages = [[[FilteredPackageTable alloc]
         initWithBook:book_
         database:database_
         title:[source label]
@@ -4390,6 +4842,35 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [delegate_ syncData];
 }
 
+- (void) complete {
+    [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
+        @"deb", @"Type",
+        href_, @"URI",
+        @"./", @"Distribution",
+    nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
+
+    [delegate_ syncData];
+}
+
+- (NSString *) getWarning {
+    NSString *href(href_);
+    NSRange colon([href rangeOfString:@"://"]);
+    if (colon.location != NSNotFound)
+        href = [href substringFromIndex:(colon.location + 3)];
+    href = [href stringByAddingPercentEscapes];
+    href = [@"http://cydia.saurik.com/api/repotag/" stringByAppendingString:href];
+    href = [href stringByCachingURLWithCurrentCDN];
+
+    NSURL *url([NSURL URLWithString:href]);
+
+    NSStringEncoding encoding;
+    NSError *error(nil);
+
+    if (NSString *warning = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error])
+        return [warning length] == 0 ? nil : warning;
+    return nil;
+}
+
 - (void) _endConnection:(NSURLConnection *)connection {
     NSURLConnection **field = NULL;
     if (connection == trivial_bz2_)
@@ -4404,21 +4885,26 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         trivial_bz2_ == nil &&
         trivial_gz_ == nil
     ) {
-        [delegate_ setStatusBarShowsProgress:NO];
-
-        [hud_ show:NO];
-        [hud_ removeFromSuperview];
-        [hud_ autorelease];
-        hud_ = nil;
+        bool defer(false);
 
         if (trivial_) {
-            [Sources_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
-                @"deb", @"Type",
-                href_, @"URI",
-                @"./", @"Distribution",
-            nil] forKey:[NSString stringWithFormat:@"deb:%@:./", href_]];
-
-            [delegate_ syncData];
+            if (NSString *warning = [self yieldToSelector:@selector(getWarning)]) {
+                defer = true;
+
+                UIActionSheet *sheet = [[[UIActionSheet alloc]
+                    initWithTitle:@"Source Warning"
+                    buttons:[NSArray arrayWithObjects:@"Add Anyway", @"Cancel", nil]
+                    defaultButtonIndex:0
+                    delegate:self
+                    context:@"warning"
+                ] autorelease];
+
+                [sheet setNumberOfRows:1];
+
+                [sheet setBodyText:warning];
+                [sheet popupAlertAnimated:YES];
+            } else
+                [self complete];
         } else if (error_ != nil) {
             UIActionSheet *sheet = [[[UIActionSheet alloc]
                 initWithTitle:@"Verification Error"
@@ -4443,8 +4929,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             [sheet popupAlertAnimated:YES];
         }
 
-        [href_ release];
-        href_ = nil;
+        [delegate_ setStatusBarShowsProgress:NO];
+        [delegate_ removeProgressHUD:hud_];
+
+        [hud_ autorelease];
+        hud_ = nil;
+
+        if (!defer) {
+            [href_ release];
+            href_ = nil;
+        }
 
         if (error_ != nil) {
             [error_ release];
@@ -4505,7 +4999,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
                 trivial_ = false;
 
-                hud_ = [delegate_ addProgressHUD];
+                hud_ = [[delegate_ addProgressHUD] retain];
                 [hud_ setText:@"Verifying URL"];
             } break;
 
@@ -4521,6 +5015,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [sheet dismiss];
     else if ([context isEqualToString:@"urlerror"])
         [sheet dismiss];
+    else if ([context isEqualToString:@"warning"]) {
+        switch (button) {
+            case 1:
+                [self complete];
+            break;
+
+            case 2:
+            break;
+
+            default:
+                _assert(false);
+        }
+
+        [href_ release];
+        href_ = nil;
+
+        [sheet dismiss];
+    }
 }
 
 - (id) initWithBook:(RVBook *)book database:(Database *)database {
@@ -4634,7 +5146,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 /* Installed View {{{ */
 @interface InstalledView : RVPage {
     _transient Database *database_;
-    PackageTable *packages_;
+    FilteredPackageTable *packages_;
     BOOL expert_;
 }
 
@@ -4653,7 +5165,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if ((self = [super initWithBook:book]) != nil) {
         database_ = database;
 
-        packages_ = [[PackageTable alloc]
+        packages_ = [[FilteredPackageTable alloc]
             initWithBook:book
             database:database
             title:nil
@@ -4734,7 +5246,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     ] autorelease];
 
     [sheet setBodyText:
-        @"Copyright (C) 2008\n"
+        @"Copyright (C) 2008-2009\n"
         "Jay Freeman (saurik)\n"
         "saurik@saurik.com\n"
         "http://www.saurik.com/\n"
@@ -4779,49 +5291,20 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 #if !AlwaysReload
 - (id) _rightButtonTitle {
-    return nil;
-}
-#endif
-
-- (bool) _loading {
-    return false;
-}
-
-@end
-/* }}} */
-
-/* Indirect Delegate {{{ */
-@interface IndirectDelegate : NSProxy {
-    _transient volatile id delegate_;
-}
-
-- (void) setDelegate:(id)delegate;
-- (id) initWithDelegate:(id)delegate;
-@end
-
-@implementation IndirectDelegate
-
-- (void) setDelegate:(id)delegate {
-    delegate_ = delegate;
+    return Queuing_ ? @"Queue" : nil;
 }
 
-- (id) initWithDelegate:(id)delegate {
-    delegate_ = delegate;
-    return self;
+- (UINavigationButtonStyle) rightButtonStyle {
+    return Queuing_ ? UINavigationButtonStyleHighlighted : UINavigationButtonStyleNormal;
 }
 
-- (NSMethodSignature*) methodSignatureForSelector:(SEL)sel {
-    if (delegate_ != nil)
-        if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
-            return sig;
-    // XXX: I fucking hate Apple so very very bad
-    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
+- (void) _rightButtonClicked {
+    [delegate_ queue];
 }
+#endif
 
-- (void) forwardInvocation:(NSInvocation *)inv {
-    SEL sel = [inv selector];
-    if (delegate_ != nil && [delegate_ respondsToSelector:sel])
-        [inv invokeWithTarget:delegate_];
+- (bool) isLoading {
+    return false;
 }
 
 @end
@@ -4841,8 +5324,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     UIProgressBar *progress_;
     UINavigationButton *cancel_;
     bool updating_;
-    size_t received_;
-    NSTimeInterval last_;
 }
 
 - (id) initWithFrame:(CGRect)frame database:(Database *)database;
@@ -4892,8 +5373,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [prompt_ setText:@"Updating Database"];
     [progress_ setProgress:0];
 
-    received_ = 0;
-    last_ = [NSDate timeIntervalSinceReferenceDate];
     updating_ = true;
     [overlay_ addSubview:cancel_];
 
@@ -5057,12 +5536,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (bool) isCancelling:(size_t)received {
-    NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
-    if (received_ != received) {
-        received_ = received;
-        last_ = now;
-    } else if (now - last_ > 15)
-        return true;
     return !updating_;
 }
 
@@ -5107,12 +5580,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) _returnPNGWithImage:(UIImage *)icon forRequest:(NSURLRequest *)request {
     id<NSURLProtocolClient> client([self client]);
-    NSData *data(UIImagePNGRepresentation(icon));
+    if (icon == nil)
+        [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]];
+    else {
+        NSData *data(UIImagePNGRepresentation(icon));
 
-    NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
-    [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
-    [client URLProtocol:self didLoadData:data];
-    [client URLProtocolDidFinishLoading:self];
+        NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
+        [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+        [client URLProtocol:self didLoadData:data];
+        [client URLProtocolDidFinishLoading:self];
+    }
 }
 
 - (void) startLoading {
@@ -5180,8 +5657,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @end
 /* }}} */
 
-/* Install View {{{ */
-@interface InstallView : RVPage {
+/* Sections View {{{ */
+@interface SectionsView : RVPage {
     _transient Database *database_;
     NSMutableArray *sections_;
     NSMutableArray *filtered_;
@@ -5197,7 +5674,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 
-@implementation InstallView
+@implementation SectionsView
 
 - (void) dealloc {
     [list_ setDataSource:nil];
@@ -5262,7 +5739,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         }
     }
 
-    PackageTable *table = [[[PackageTable alloc]
+    PackageTable *table = [[[FilteredPackageTable alloc]
         initWithBook:book_
         database:database_
         title:title
@@ -5317,8 +5794,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     NSMutableDictionary *sections = [NSMutableDictionary dictionaryWithCapacity:32];
 
     _trace();
-    for (size_t i(0); i != [packages count]; ++i) {
-        Package *package([packages objectAtIndex:i]);
+    for (Package *package in packages) {
         NSString *name([package section]);
 
         if (name != nil) {
@@ -5342,8 +5818,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     _trace();
 
     Section *section = nil;
-    for (size_t offset = 0, count = [filtered count]; offset != count; ++offset) {
-        Package *package = [filtered objectAtIndex:offset];
+    for (Package *package in filtered) {
         NSString *name = [package section];
 
         if (section == nil || name != nil && ![[section name] isEqualToString:name]) {
@@ -5518,15 +5993,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [sections_ removeAllObjects];
 
     _trace();
-    for (size_t i(0); i != [packages count]; ++i) {
-        Package *package([packages objectAtIndex:i]);
-
+    for (Package *package in packages)
         if (
             [package installed] == nil && [package valid] && [package visible] ||
-            [package upgradableAndEssential:NO]
+            [package upgradableAndEssential:YES]
         )
             [packages_ addObject:package];
-    }
 
     _trace();
     [packages_ radixSortUsingSelector:@selector(compareForChanges) withObject:nil];
@@ -5553,10 +6025,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             if (section == nil || last != seen && (seen == nil || [seen compare:last] != NSOrderedSame)) {
                 last = seen;
 
-                NSString *name(seen == nil ? [@"n/a ?" retain] : (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen));
+                NSString *name;
+                if (seen == nil)
+                    name = @"unknown?";
+                else {
+                    name = (NSString *) CFDateFormatterCreateStringWithDate(NULL, formatter, (CFDateRef) seen);
+                    [name autorelease];
+                }
+
+                name = [@"New at " stringByAppendingString:name];
                 section = [[[Section alloc] initWithName:name row:offset] autorelease];
                 [sections_ addObject:section];
-                [name release];
             }
 
             [section addToCount];
@@ -5614,7 +6093,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     UIView *accessory_;
     UISearchField *field_;
     UITransitionView *transition_;
-    PackageTable *table_;
+    FilteredPackageTable *table_;
     UIPreferencesTable *advanced_;
     UIView *dimmed_;
     bool flipped_;
@@ -5745,7 +6224,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         CGColor dimmed(space_, 0, 0, 0, 0.5);
         [dimmed_ setBackgroundColor:[UIColor colorWithCGColor:dimmed]];
 
-        table_ = [[PackageTable alloc]
+        table_ = [[FilteredPackageTable alloc]
             initWithBook:book
             database:database
             title:nil
@@ -5839,7 +6318,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if (flipped_)
         [self flipPage];
     [table_ setObject:[field_ text]];
-    [table_ reloadData];
+    _profile(SearchView$reloadData)
+        [table_ reloadData];
+    _end
+    PrintTimes();
     [table_ resetCursor];
 }
 
@@ -6120,7 +6602,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     UIKeyboard *keyboard_;
     UIProgressHUD *hud_;
 
-    InstallView *install_;
+    SectionsView *sections_;
     ChangesView *changes_;
     ManageView *manage_;
     SearchView *search_;
@@ -6168,12 +6650,17 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) _reloadData {
-    /*UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
-    [hud setText:@"Reloading Data"];
-    [overlay_ addSubview:hud];
-    [hud show:YES];*/
+    UIView *block();
 
-    [database_ reloadData];
+    static bool loaded(false);
+    UIProgressHUD *hud([self addProgressHUD]);
+    [hud setText:(loaded ? @"Reloading Data" : @"Loading Data")];
+    loaded = true;
+
+    [database_ yieldToSelector:@selector(reloadData) withObject:nil];
+    _trace();
+
+    [self removeProgressHUD:hud];
 
     size_t changes(0);
 
@@ -6195,7 +6682,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         NSString *badge([[NSNumber numberWithInt:changes] stringValue]);
         [buttonbar_ setBadgeValue:badge forButton:3];
         if ([buttonbar_ respondsToSelector:@selector(setBadgeAnimated:forButton:)])
-            [buttonbar_ setBadgeAnimated:YES forButton:3];
+            [buttonbar_ setBadgeAnimated:([essential_ count] != 0) forButton:3];
         [self setApplicationBadge:badge];
     } else {
         [buttonbar_ setBadgeValue:nil forButton:3];
@@ -6204,22 +6691,26 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [self removeApplicationBadge];
     }
 
+    Queuing_ = false;
+    [buttonbar_ setBadgeValue:nil forButton:4];
+
     [self updateData];
 
-#if !ForSaurik
+    // XXX: what is this line of code for?
     if ([packages count] == 0);
-    else if (Loaded_)
-#endif
+    else if (Loaded_ || ManualRefresh) loaded:
         [self _loaded];
-#if !ForSaurik
     else {
         Loaded_ = YES;
+
+        if (NSDate *update = [Metadata_ objectForKey:@"LastUpdate"]) {
+            NSTimeInterval interval([update timeIntervalSinceNow]);
+            if (interval <= 0 && interval > -600)
+                goto loaded;
+        }
+
         [book_ update];
     }
-#endif
-
-    /*[hud show:NO];
-    [hud removeFromSuperview];*/
 }
 
 - (void) _saveConfig {
@@ -6235,8 +6726,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [self _saveConfig];
 
     /* XXX: this is just stupid */
-    if (tag_ != 2 && install_ != nil)
-        [install_ reloadData];
+    if (tag_ != 2 && sections_ != nil)
+        [sections_ reloadData];
     if (tag_ != 3 && changes_ != nil)
         [changes_ reloadData];
     if (tag_ != 5 && search_ != nil)
@@ -6255,8 +6746,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     NSArray *keys = [Sources_ allKeys];
 
-    for (int i(0), e([keys count]); i != e; ++i) {
-        NSString *key = [keys objectAtIndex:i];
+    for (NSString *key in keys) {
         NSDictionary *source = [Sources_ objectForKey:key];
 
         fprintf(file, "%s %s %s\n",
@@ -6293,17 +6783,39 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         _error->Discard();
 }
 
+- (void) popUpBook:(RVBook *)book {
+    [underlay_ popSubview:book];
+}
+
+- (CGRect) popUpBounds {
+    return [underlay_ bounds];
+}
+
 - (void) perform {
     [database_ prepare];
 
-    confirm_ = [[RVBook alloc] initWithFrame:[underlay_ bounds]];
+    confirm_ = [[RVBook alloc] initWithFrame:[self popUpBounds]];
     [confirm_ setDelegate:self];
 
     ConfirmationView *page([[[ConfirmationView alloc] initWithBook:confirm_ database:database_] autorelease]);
     [page setDelegate:self];
 
     [confirm_ setPage:page];
-    [underlay_ popSubview:confirm_];
+    [self popUpBook:confirm_];
+}
+
+- (void) queue {
+    @synchronized (self) {
+        [self perform];
+    }
+}
+
+- (void) clearPackage:(Package *)package {
+    @synchronized (self) {
+        [package clear];
+        [self resolve];
+        [self perform];
+    }
 }
 
 - (void) installPackage:(Package *)package {
@@ -6330,8 +6842,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) cancel {
+    [self slideUp:[[[UIActionSheet alloc]
+        initWithTitle:nil
+        buttons:[NSArray arrayWithObjects:@"Continue Queuing", @"Cancel and Clear", nil]
+        defaultButtonIndex:1
+        delegate:self
+        context:@"cancel"
+    ] autorelease]];
+}
+
+- (void) complete {
     @synchronized (self) {
         [self _reloadData];
+
         if (confirm_ != nil) {
             [confirm_ release];
             confirm_ = nil;
@@ -6373,7 +6896,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [confirm_ popFromSuperviewAnimated:NO];
     }
 
-    [self cancel];
+    [self complete];
 }
 
 - (void) setPage:(RVPage *)page {
@@ -6398,12 +6921,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [book_ resetViewAnimated:YES];
         return;
     } else if (tag_ == 2 && tag != 2)
-        [install_ resetView];
+        [sections_ resetView];
 
     switch (tag) {
         case 1: [self _setHomePage]; break;
 
-        case 2: [self setPage:install_]; break;
+        case 2: [self setPage:sections_]; break;
         case 3: [self setPage:changes_]; break;
         case 4: [self setPage:manage_]; break;
         case 5: [self setPage:search_]; break;
@@ -6439,9 +6962,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) finish {
     if (hud_ != nil) {
         [self setStatusBarShowsProgress:NO];
+        [self removeProgressHUD:hud_];
 
-        [hud_ show:NO];
-        [hud_ removeFromSuperview];
         [hud_ autorelease];
         hud_ = nil;
 
@@ -6459,6 +6981,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         return;
     }
 
+    _trace();
     overlay_ = [[UIView alloc] initWithFrame:[underlay_ bounds]];
 
     CGRect screenrect = [UIHardware fullScreenApplicationContentRect];
@@ -6559,7 +7082,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     [self reloadData];
 
-    install_ = [[InstallView alloc] initWithBook:book_ database:database_];
+    sections_ = [[SectionsView alloc] initWithBook:book_ database:database_];
     changes_ = [[ChangesView alloc] initWithBook:book_ database:database_];
     search_ = [[SearchView alloc] initWithBook:book_ database:database_];
 
@@ -6568,6 +7091,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         withClass:[ManageView class]
     ] retain];
 
+    PrintTimes();
+
     if (bootstrap_)
         [self bootstrap];
     else
@@ -6577,12 +7102,45 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
     NSString *context([sheet context]);
 
-    if ([context isEqualToString:@"fixhalf"]) {
+    if ([context isEqualToString:@"missing"])
+        [sheet dismiss];
+    else if ([context isEqualToString:@"cancel"]) {
+        bool clear;
+
+        switch (button) {
+            case 1:
+                clear = false;
+            break;
+
+            case 2:
+                clear = true;
+            break;
+
+            default:
+                _assert(false);
+        }
+
+        [sheet dismiss];
+
+        @synchronized (self) {
+            if (clear)
+                [self _reloadData];
+            else {
+                Queuing_ = true;
+                [buttonbar_ setBadgeValue:@"Q'd" forButton:4];
+                [book_ reloadData];
+            }
+
+            if (confirm_ != nil) {
+                [confirm_ release];
+                confirm_ = nil;
+            }
+        }
+    } else if ([context isEqualToString:@"fixhalf"]) {
         switch (button) {
             case 1:
                 @synchronized (self) {
-                    for (int i = 0, e = [broken_ count]; i != e; ++i) {
-                        Package *broken = [broken_ objectAtIndex:i];
+                    for (Package *broken in broken_) {
                         [broken remove];
 
                         NSString *id = [broken id];
@@ -6638,10 +7196,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         switch (button) {
             case 1:
                 @synchronized (self) {
-                    for (int i = 0, e = [essential_ count]; i != e; ++i) {
-                        Package *essential = [essential_ objectAtIndex:i];
+                    for (Package *essential in essential_)
                         [essential install];
-                    }
 
                     [self resolve];
                     [self perform];
@@ -6685,12 +7241,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (UIProgressHUD *) addProgressHUD {
-    UIProgressHUD *hud = [[UIProgressHUD alloc] initWithWindow:window_];
+    UIProgressHUD *hud([[[UIProgressHUD alloc] initWithWindow:window_] autorelease]);
+    [window_ setUserInteractionEnabled:NO];
     [hud show:YES];
-    [underlay_ addSubview:hud];
+    [progress_ addSubview:hud];
     return hud;
 }
 
+- (void) removeProgressHUD:(UIProgressHUD *)hud {
+    [hud show:NO];
+    [hud removeFromSuperview];
+    [window_ setUserInteractionEnabled:YES];
+}
+
 - (void) openMailToURL:(NSURL *)url {
 // XXX: this makes me sad
 #if 0
@@ -6729,31 +7292,39 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag {
-    NSString *href = [url absoluteString];
-
     if (tag != NULL)
         tag = 0;
 
-    if ([href isEqualToString:@"cydia://add-source"])
+    NSString *scheme([[url scheme] lowercaseString]);
+    if (![scheme isEqualToString:@"cydia"])
+        return nil;
+    NSString *path([url absoluteString]);
+    if ([path length] < 8)
+        return nil;
+    path = [path substringFromIndex:8];
+    if (![path hasPrefix:@"/"])
+        path = [@"/" stringByAppendingString:path];
+
+    if ([path isEqualToString:@"/add-source"])
         return [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
-    else if ([href isEqualToString:@"cydia://storage"])
+    else if ([path isEqualToString:@"/storage"])
         return [self _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]] withClass:[BrowserView class]];
-    else if ([href isEqualToString:@"cydia://sources"])
+    else if ([path isEqualToString:@"/sources"])
         return [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
-    else if ([href isEqualToString:@"cydia://packages"])
+    else if ([path isEqualToString:@"/packages"])
         return [[[InstalledView alloc] initWithBook:book_ database:database_] autorelease];
-    else if ([href hasPrefix:@"cydia://url/"])
-        return [self _pageForURL:[NSURL URLWithString:[href substringFromIndex:12]] withClass:[BrowserView class]];
-    else if ([href hasPrefix:@"cydia://launch/"])
-        [self launchApplicationWithIdentifier:[href substringFromIndex:15] suspended:NO];
-    else if ([href hasPrefix:@"cydia://package-settings/"])
-        return [[[SettingsView alloc] initWithBook:book_ database:database_ package:[href substringFromIndex:25]] autorelease];
-    else if ([href hasPrefix:@"cydia://package-signature/"])
-        return [[[SignatureView alloc] initWithBook:book_ database:database_ package:[href substringFromIndex:26]] autorelease];
-    else if ([href hasPrefix:@"cydia://package/"])
-        return [self pageForPackage:[href substringFromIndex:16]];
-    else if ([href hasPrefix:@"cydia://files/"]) {
-        NSString *name = [href substringFromIndex:14];
+    else if ([path hasPrefix:@"/url/"])
+        return [self _pageForURL:[NSURL URLWithString:[path substringFromIndex:5]] withClass:[BrowserView class]];
+    else if ([path hasPrefix:@"/launch/"])
+        [self launchApplicationWithIdentifier:[path substringFromIndex:8] suspended:NO];
+    else if ([path hasPrefix:@"/package-settings/"])
+        return [[[SettingsView alloc] initWithBook:book_ database:database_ package:[path substringFromIndex:18]] autorelease];
+    else if ([path hasPrefix:@"/package-signature/"])
+        return [[[SignatureView alloc] initWithBook:book_ database:database_ package:[path substringFromIndex:19]] autorelease];
+    else if ([path hasPrefix:@"/package/"])
+        return [self pageForPackage:[path substringFromIndex:9]];
+    else if ([path hasPrefix:@"/files/"]) {
+        NSString *name = [path substringFromIndex:7];
 
         if (Package *package = [database_ packageWithName:name]) {
             FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
@@ -6776,6 +7347,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) applicationDidFinishLaunching:(id)unused {
+    _trace();
     Font12_ = [[UIFont systemFontOfSize:12] retain];
     Font12Bold_ = [[UIFont boldSystemFontOfSize:12] retain];
     Font14_ = [[UIFont systemFontOfSize:14] retain];
@@ -6820,7 +7392,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     ) {
         [self setIdleTimerDisabled:YES];
 
-        hud_ = [self addProgressHUD];
+        hud_ = [[self addProgressHUD] retain];
         [hud_ setText:@"Reorganizing\n\nWill Automatically\nClose When Done"];
 
         [self setStatusBarShowsProgress:YES];
@@ -6876,8 +7448,7 @@ void AddPreferences(NSString *plist) { _pooled
 
     bool cydia(false);
 
-    for (size_t i(0); i != [items count]; ++i) {
-        NSMutableDictionary *item([items objectAtIndex:i]);
+    for (NSMutableDictionary *item in items) {
         NSString *label = [item objectForKey:@"label"];
         if (label != nil && [label isEqualToString:@"Cydia"]) {
             cydia = true;
@@ -6921,6 +7492,7 @@ id Dealloc_(id self, SEL selector) {
 }*/
 
 int main(int argc, char *argv[]) { _pooled
+    _trace();
     class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16");
 
     bool substrate(false);
@@ -6999,19 +7571,19 @@ int main(int argc, char *argv[]) { _pooled
 
     if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"])
         Build_ = [system objectForKey:@"ProductBuildVersion"];
+    if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) {
+        Product_ = [info objectForKey:@"SafariProductVersion"];
+        Safari_ = [info objectForKey:@"CFBundleVersion"];
+    }
 
     /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
     AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
 
-    /*if ((Indices_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/indices.plist"]) == NULL)
-        Indices_ = [[NSMutableDictionary alloc] init];*/
-
-    Indices_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
-        @"http://"/*"cache.saurik.com/"*/"cydia.saurik.com/server/rating/@", @"Rating",
-        @"http://"/*"cache.saurik.com/"*/"cydia.saurik.com/repotag/@", @"RepoTag",
-    nil];
+    _trace();
+    Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"];
+    _trace();
 
-    if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
+    if (Metadata_ == NULL)
         Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
     else {
         Settings_ = [Metadata_ objectForKey:@"Settings"];
@@ -7048,8 +7620,11 @@ int main(int argc, char *argv[]) { _pooled
     /*if (substrate && access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
         dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);*/
 
-    if (access("/User", F_OK) != 0)
+    if (access("/User", F_OK) != 0) {
+        _trace();
         system("/usr/libexec/cydia/firmware.sh");
+        _trace();
+    }
 
     _assert([[NSFileManager defaultManager]
         createDirectoryAtPath:@"/var/cache/apt/archives/partial"
@@ -7066,6 +7641,19 @@ int main(int argc, char *argv[]) { _pooled
     Off_.Set(space_, 0.9, 0.9, 0.9, 1.0);
     White_.Set(space_, 1.0, 1.0, 1.0, 1.0);
     Gray_.Set(space_, 0.4, 0.4, 0.4, 1.0);
+    Green_.Set(space_, 0.0, 0.5, 0.0, 1.0);
+    Purple_.Set(space_, 0.0, 0.0, 0.7, 1.0);
+    Purplish_.Set(space_, 0.4, 0.4, 0.8, 1.0);
+    /*Purple_.Set(space_, 1.0, 0.3, 0.0, 1.0);
+    Purplish_.Set(space_, 1.0, 0.6, 0.4, 1.0); ORANGE */
+    /*Purple_.Set(space_, 1.0, 0.5, 0.0, 1.0);
+    Purplish_.Set(space_, 1.0, 0.7, 0.2, 1.0); ORANGISH */
+    /*Purple_.Set(space_, 0.5, 0.0, 0.7, 1.0);
+    Purplish_.Set(space_, 0.7, 0.4, 0.8, 1.0); PURPLE */
+
+//.93
+    InstallingColor_ = [UIColor colorWithRed:0.88f green:1.00f blue:0.88f alpha:1.00f];
+    RemovingColor_ = [UIColor colorWithRed:1.00f green:0.88f blue:0.88f alpha:1.00f];
 
     Finishes_ = [NSArray arrayWithObjects:@"return", @"reopen", @"restart", @"reload", @"reboot", nil];
 
@@ -7074,6 +7662,7 @@ int main(int argc, char *argv[]) { _pooled
     UIApplicationUseLegacyEvents(YES);
     UIKeyboardDisableAutomaticAppearance();
 
+    _trace();
     int value = UIApplicationMain(argc, argv, @"Cydia", @"Cydia");
 
     CGColorSpaceRelease(space_);