]> git.saurik.com Git - cydia.git/blobdiff - Cydia.mm
Gracefully handle someone /deleting/ the firmware package.
[cydia.git] / Cydia.mm
index f94557abda15942a59a436d9b366a013de5e8c19..7a5a33d130aaf5e2f0dac2a48c909c4ae4c744c7 100644 (file)
--- a/Cydia.mm
+++ b/Cydia.mm
@@ -35,6 +35,9 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+// XXX: wtf/FastMalloc.h... wtf?
+#define USE_SYSTEM_MALLOC 1
+
 /* #include Directives {{{ */
 #import "UICaboodle.h"
 
 /* #include Directives {{{ */
 #import "UICaboodle.h"
 
 // XXX: remove
 #import <MessageUI/MailComposeController.h>
 
 // XXX: remove
 #import <MessageUI/MailComposeController.h>
 
-#import <WebCore/WebScriptObject.h>
-//#include <WebCore/DOMHTML.h>
-
-#include <WebKit/WebFrame.h>
-#include <WebKit/WebPolicyDelegate.h>
-#include <WebKit/WebView.h>
-
-#import <WebKit/WebView-WebPrivate.h>
-
 #include <sstream>
 #include <string>
 
 #include <sstream>
 #include <string>
 
@@ -85,6 +79,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
 
 #include <notify.h>
 #include <dlfcn.h>
 
 #include <notify.h>
 #include <dlfcn.h>
@@ -102,6 +98,8 @@ extern "C" {
 
 #import "BrowserView.h"
 #import "ResetView.h"
 
 #import "BrowserView.h"
 #import "ResetView.h"
+
+#import "substrate.h"
 /* }}} */
 
 //#define _finline __attribute__((force_inline))
 /* }}} */
 
 //#define _finline __attribute__((force_inline))
@@ -116,6 +114,14 @@ bool _itv;
         exit(0); \
 } while (false)
 
         exit(0); \
 } while (false)
 
+static uint64_t profile_;
+
+#define _timestamp ({ \
+    struct timeval tv; \
+    gettimeofday(&tv, NULL); \
+    tv.tv_sec * 1000000 + tv.tv_usec; \
+})
+
 /* Objective-C Handle<> {{{ */
 template <typename Type_>
 class _H {
 /* Objective-C Handle<> {{{ */
 template <typename Type_>
 class _H {
@@ -158,11 +164,18 @@ class _H {
 
 #define _pooled _H<NSAutoreleasePool> _pool([[NSAutoreleasePool alloc] init], true);
 
 
 #define _pooled _H<NSAutoreleasePool> _pool([[NSAutoreleasePool alloc] init], true);
 
+void NSLogPoint(const char *fix, const CGPoint &point) {
+    NSLog(@"%s(%g,%g)", fix, point.x, point.y);
+}
+
 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);
 }
 
 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);
 }
 
-static const NSStringCompareOptions CompareOptions_ = NSCaseInsensitiveSearch | NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch;
+/* NSForcedOrderingSearch doesn't work on the iPhone */
+static const NSStringCompareOptions BaseCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch;
+static const NSStringCompareOptions ForcedCompareOptions_ = BaseCompareOptions_;
+static const NSStringCompareOptions LaxCompareOptions_ = BaseCompareOptions_ | NSCaseInsensitiveSearch;
 
 /* iPhoneOS 2.0 Compatibility {{{ */
 #ifdef __OBJC2__
 
 /* iPhoneOS 2.0 Compatibility {{{ */
 #ifdef __OBJC2__
@@ -249,17 +262,20 @@ extern NSString * const kCAFilterNearest;
 
 #define lprintf(args...) fprintf(stderr, args)
 
 
 #define lprintf(args...) fprintf(stderr, args)
 
-#define ForSaurik 1
+#define ForRelease 0
+#define ForSaurik (1 && !ForRelease)
+#define IgnoreInstall (0 && !ForRelease)
 #define RecycleWebViews 0
 #define RecycleWebViews 0
+#define AlwaysReload (1 && !ForRelease)
 
 /* Radix Sort {{{ */
 @interface NSMutableArray (Radix)
 
 /* Radix Sort {{{ */
 @interface NSMutableArray (Radix)
-- (void) radixUsingSelector:(SEL)selector withObject:(id)object;
+- (void) radixSortUsingSelector:(SEL)selector withObject:(id)object;
 @end
 
 @implementation NSMutableArray (Radix)
 
 @end
 
 @implementation NSMutableArray (Radix)
 
-- (void) radixUsingSelector:(SEL)selector withObject:(id)object {
+- (void) radixSortUsingSelector:(SEL)selector withObject:(id)object {
     NSInvocation *invocation([NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:"L12@0:4@8"]]);
     [invocation setSelector:selector];
     [invocation setArgument:&object atIndex:2];
     NSInvocation *invocation([NSInvocation invocationWithMethodSignature:[NSMethodSignature signatureWithObjCTypes:"L12@0:4@8"]]);
     [invocation setSelector:selector];
     [invocation setArgument:&object atIndex:2];
@@ -282,9 +298,10 @@ extern NSString * const kCAFilterNearest;
         [invocation getReturnValue:&item.key];
     }
 
         [invocation getReturnValue:&item.key];
     }
 
+    static const size_t width = 32;
     static const size_t bits = 11;
     static const size_t slots = 1 << bits;
     static const size_t bits = 11;
     static const size_t slots = 1 << bits;
-    static const size_t passes = (32 + (bits - 1)) / bits;
+    static const size_t passes = (width + (bits - 1)) / bits;
 
     size_t *hist(new size_t[slots]);
 
 
     size_t *hist(new size_t[slots]);
 
@@ -294,7 +311,7 @@ extern NSString * const kCAFilterNearest;
         for (size_t i(0); i != count; ++i) {
             uint32_t key(lhs[i].key);
             key >>= pass * bits;
         for (size_t i(0); i != count; ++i) {
             uint32_t key(lhs[i].key);
             key >>= pass * bits;
-            key &= _not(uint32_t) >> 32 - bits;
+            key &= _not(uint32_t) >> width - bits;
             ++hist[key];
         }
 
             ++hist[key];
         }
 
@@ -308,7 +325,7 @@ extern NSString * const kCAFilterNearest;
         for (size_t i(0); i != count; ++i) {
             uint32_t key(lhs[i].key);
             key >>= pass * bits;
         for (size_t i(0); i != count; ++i) {
             uint32_t key(lhs[i].key);
             key >>= pass * bits;
-            key &= _not(uint32_t) >> 32 - bits;
+            key &= _not(uint32_t) >> width - bits;
             rhs[hist[key]++] = lhs[i];
         }
 
             rhs[hist[key]++] = lhs[i];
         }
 
@@ -330,6 +347,34 @@ extern NSString * const kCAFilterNearest;
 @end
 /* }}} */
 
 @end
 /* }}} */
 
+/* Apple Bug Fixes {{{ */
+@implementation UIWebDocumentView (Cydia)
+
+- (void) _setScrollerOffset:(CGPoint)offset {
+    UIScroller *scroller([self _scroller]);
+
+    CGSize size([scroller contentSize]);
+    CGSize bounds([scroller bounds].size);
+
+    CGPoint max;
+    max.x = size.width - bounds.width;
+    max.y = size.height - bounds.height;
+
+    // wtf Apple?!
+    if (max.x < 0)
+        max.x = 0;
+    if (max.y < 0)
+        max.y = 0;
+
+    offset.x = offset.x < 0 ? 0 : offset.x > max.x ? max.x : offset.x;
+    offset.y = offset.y < 0 ? 0 : offset.y > max.y ? max.y : offset.y;
+
+    [scroller setOffset:offset];
+}
+
+@end
+/* }}} */
+
 typedef enum {
     kUIControlEventMouseDown = 1 << 0,
     kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
 typedef enum {
     kUIControlEventMouseDown = 1 << 0,
     kUIControlEventMouseMovedInside = 1 << 2, // mouse moved inside control target
@@ -339,6 +384,19 @@ typedef enum {
     kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
 } UIControlEventMasks;
 
     kUIControlAllEvents = (kUIControlEventMouseDown | kUIControlEventMouseMovedInside | kUIControlEventMouseMovedOutside | kUIControlEventMouseUpInside | kUIControlEventMouseUpOutside)
 } UIControlEventMasks;
 
+NSUInteger DOMNodeList$countByEnumeratingWithState$objects$count$(DOMNodeList *self, SEL sel, NSFastEnumerationState *state, id *objects, NSUInteger count) {
+    size_t length([self length] - state->state);
+    if (length <= 0)
+        return 0;
+    else if (length > count)
+        length = count;
+    for (size_t i(0); i != length; ++i)
+        objects[i] = [self item:state->state++];
+    state->itemsPtr = objects;
+    state->mutationsPtr = (unsigned long *) self;
+    return length;
+}
+
 @interface NSString (UIKit)
 - (NSString *) stringByAddingPercentEscapes;
 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
 @interface NSString (UIKit)
 - (NSString *) stringByAddingPercentEscapes;
 - (NSString *) stringByReplacingCharacter:(unsigned short)arg0 withCharacter:(unsigned short)arg1;
@@ -352,10 +410,7 @@ typedef enum {
 @implementation NSString (Cydia)
 
 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
 @implementation NSString (Cydia)
 
 + (NSString *) stringWithUTF8Bytes:(const char *)bytes length:(int)length {
-    char data[length + 1];
-    memcpy(data, bytes, length);
-    data[length] = '\0';
-    return [NSString stringWithUTF8String:data];
+    return [[[NSString alloc] initWithBytes:bytes length:length encoding:NSUTF8StringEncoding] autorelease];
 }
 
 - (NSComparisonResult) compareByPath:(NSString *)other {
 }
 
 - (NSComparisonResult) compareByPath:(NSString *)other {
@@ -548,6 +603,7 @@ static const float KeyboardTime_ = 0.3f;
 
 #define SpringBoard_ "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
 #define SandboxTemplate_ "/usr/share/sandbox/SandboxTemplate.sb"
 
 #define SpringBoard_ "/System/Library/LaunchDaemons/com.apple.SpringBoard.plist"
 #define SandboxTemplate_ "/usr/share/sandbox/SandboxTemplate.sb"
+#define NotifyConfig_ "/etc/notify.conf"
 
 static CGColor Blue_;
 static CGColor Blueish_;
 
 static CGColor Blue_;
 static CGColor Blueish_;
@@ -573,25 +629,18 @@ static UIFont *Font18Bold_;
 static UIFont *Font22Bold_;
 
 static const char *Machine_ = NULL;
 static UIFont *Font22Bold_;
 
 static const char *Machine_ = NULL;
-static const NSString *UniqueID_ = NULL;
-
-unsigned Major_;
-unsigned Minor_;
-unsigned BugFix_;
+static const NSString *UniqueID_ = nil;
+static const NSString *Build_ = nil;
 
 CFLocaleRef Locale_;
 CGColorSpaceRef space_;
 
 
 CFLocaleRef Locale_;
 CGColorSpaceRef space_;
 
-#define FW_LEAST(major, minor, bugfix) \
-    (major < Major_ || major == Major_ && \
-        (minor < Minor_ || minor == Minor_ && \
-            bugfix <= BugFix_))
-
 bool bootstrap_;
 bool reload_;
 
 static NSDictionary *SectionMap_;
 static NSMutableDictionary *Metadata_;
 bool bootstrap_;
 bool reload_;
 
 static NSDictionary *SectionMap_;
 static NSMutableDictionary *Metadata_;
+static NSMutableDictionary *Indices_;
 static _transient NSMutableDictionary *Settings_;
 static _transient NSString *Role_;
 static _transient NSMutableDictionary *Packages_;
 static _transient NSMutableDictionary *Settings_;
 static _transient NSString *Role_;
 static _transient NSMutableDictionary *Packages_;
@@ -716,6 +765,7 @@ bool isSectionVisible(NSString *section) {
 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag;
 - (RVPage *) pageForPackage:(NSString *)name;
 - (void) openMailToURL:(NSURL *)url;
 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag;
 - (RVPage *) pageForPackage:(NSString *)name;
 - (void) openMailToURL:(NSURL *)url;
+- (void) clearFirstResponder;
 @end
 /* }}} */
 
 @end
 /* }}} */
 
@@ -744,6 +794,7 @@ class Status :
     }
 
     virtual void Fetch(pkgAcquire::ItemDesc &item) {
     }
 
     virtual void Fetch(pkgAcquire::ItemDesc &item) {
+        //NSString *name([NSString stringWithUTF8String:item.ShortDesc.c_str()]);
         [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
     }
 
         [delegate_ setProgressTitle:[NSString stringWithUTF8String:("Downloading " + item.ShortDesc).c_str()]];
     }
 
@@ -1014,7 +1065,7 @@ class Progress :
             return NSOrderedDescending;
     }
 
             return NSOrderedDescending;
     }
 
-    return [lhs compare:rhs options:CompareOptions_];
+    return [lhs compare:rhs options:LaxCompareOptions_];
 }
 
 - (NSDictionary *) record {
 }
 
 - (NSDictionary *) record {
@@ -1107,35 +1158,6 @@ class Progress :
 @end
 /* }}} */
 /* Package Class {{{ */
 @end
 /* }}} */
 /* Package Class {{{ */
-NSString *Scour(const char *field, const char *begin, const char *end) {
-    size_t i(0), l(strlen(field));
-
-    for (;;) {
-        const char *name = begin + i;
-        const char *colon = name + l;
-        const char *value = colon + 1;
-
-        if (
-            value < end &&
-            *colon == ':' &&
-            strncasecmp(name, field, l) == 0
-        ) {
-            while (value != end && value[0] == ' ')
-                ++value;
-            const char *line = std::find(value, end, '\n');
-            while (line != value && line[-1] == ' ')
-                --line;
-
-            return [NSString stringWithUTF8Bytes:value length:(line - value)];
-        } else {
-            begin = std::find(begin, end, '\n');
-            if (begin == end)
-                return nil;
-            ++begin;
-        }
-    }
-}
-
 @interface Package : NSObject {
     pkgCache::PkgIterator iterator_;
     _transient Database *database_;
 @interface Package : NSObject {
     pkgCache::PkgIterator iterator_;
     _transient Database *database_;
@@ -1213,6 +1235,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
 
 - (Source *) source;
 - (NSString *) role;
 
 - (Source *) source;
 - (NSString *) role;
+- (NSString *) rating;
 
 - (BOOL) matches:(NSString *)text;
 
 
 - (BOOL) matches:(NSString *)text;
 
@@ -1275,7 +1298,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
 }
 
 + (NSArray *) _attributeKeys {
 }
 
 + (NSArray *) _attributeKeys {
-    return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil];
+    return [NSArray arrayWithObjects:@"applications", @"author", @"depiction", @"description", @"essential", @"homepage", @"icon", @"id", @"installed", @"latest", @"maintainer", @"name", @"purposes", @"rating", @"section", @"size", @"source", @"sponsor", @"tagline", @"warnings", nil];
 }
 
 - (NSArray *) attributeKeys {
 }
 
 - (NSArray *) attributeKeys {
@@ -1293,7 +1316,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
 
         version_ = [database_ policy]->GetCandidateVer(iterator_);
         NSString *latest = version_.end() ? nil : [NSString stringWithUTF8String:version_.VerStr()];
 
         version_ = [database_ policy]->GetCandidateVer(iterator_);
         NSString *latest = version_.end() ? nil : [NSString stringWithUTF8String:version_.VerStr()];
-        latest_ = [StripVersion(latest) retain];
+        latest_ = latest == nil ? nil : [StripVersion(latest) retain];
 
         pkgCache::VerIterator current = iterator_.CurrentVer();
         NSString *installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()];
 
         pkgCache::VerIterator current = iterator_.CurrentVer();
         NSString *installed = current.end() ? nil : [NSString stringWithUTF8String:current.VerStr()];
@@ -1314,32 +1337,77 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
             const char *begin, *end;
             parser->GetRec(begin, end);
 
             const char *begin, *end;
             parser->GetRec(begin, end);
 
-            name_ = Scour("name", 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;
+                            }
+                    }
+
+                    if (begin == NULL)
+                        break;
+                    ++begin;
+                } else goto next;
+
             if (name_ != nil)
                 name_ = [name_ retain];
             tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
             if (name_ != nil)
                 name_ = [name_ retain];
             tagline_ = [[NSString stringWithUTF8String:parser->ShortDesc().c_str()] retain];
-            icon_ = Scour("icon", begin, end);
             if (icon_ != nil)
                 icon_ = [icon_ retain];
             if (icon_ != nil)
                 icon_ = [icon_ retain];
-            depiction_ = Scour("depiction", begin, end);
             if (depiction_ != nil)
                 depiction_ = [depiction_ retain];
             if (depiction_ != nil)
                 depiction_ = [depiction_ retain];
-            homepage_ = Scour("homepage", begin, end);
             if (homepage_ == nil)
             if (homepage_ == nil)
-                homepage_ = Scour("website", begin, end);
+                homepage_ = website;
             if ([homepage_ isEqualToString:depiction_])
                 homepage_ = nil;
             if (homepage_ != nil)
                 homepage_ = [homepage_ retain];
             if ([homepage_ isEqualToString:depiction_])
                 homepage_ = nil;
             if (homepage_ != nil)
                 homepage_ = [homepage_ retain];
-            NSString *sponsor = Scour("sponsor", begin, end);
             if (sponsor != nil)
                 sponsor_ = [[Address addressWithString:sponsor] retain];
             if (sponsor != nil)
                 sponsor_ = [[Address addressWithString:sponsor] retain];
-            NSString *author = Scour("author", begin, end);
             if (author != nil)
                 author_ = [[Address addressWithString:author] retain];
             if (author != nil)
                 author_ = [[Address addressWithString:author] retain];
-            NSString *tags = Scour("tag", begin, end);
-            if (tags != nil)
-                tags_ = [[tags componentsSeparatedByString:@", "] retain];
+            if (tag != nil)
+                tags_ = [[tag componentsSeparatedByString:@", "] retain];
         }
 
         if (tags_ != nil)
         }
 
         if (tags_ != nil)
@@ -1516,10 +1584,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
 
     if (current.end())
         return essential && [self essential];
 
     if (current.end())
         return essential && [self essential];
-    else {
-        pkgCache::VerIterator candidate = [database_ policy]->GetCandidateVer(iterator_);
-        return !candidate.end() && candidate != current;
-    }
+    else
+        return !version_.end() && version_ != current;
 }
 
 - (BOOL) essential {
 }
 
 - (BOOL) essential {
@@ -1663,6 +1729,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
         [warnings addObject:@"illegal package identifier"];
     else for (size_t i(0); i != length; ++i)
         if (
         [warnings addObject:@"illegal package identifier"];
     else for (size_t i(0); i != length; ++i)
         if (
+            /* XXX: technically this is not allowed */
+            (name[i] < 'A' || name[i] > 'Z') &&
             (name[i] < 'a' || name[i] > 'z') &&
             (name[i] < '0' || name[i] > '9') &&
             (i == 0 || name[i] != '+' && name[i] != '-' && name[i] != '.')
             (name[i] < 'a' || name[i] > 'z') &&
             (name[i] < '0' || name[i] > '9') &&
             (i == 0 || name[i] != '+' && name[i] != '-' && name[i] != '.')
@@ -1670,17 +1738,25 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
 
     if (strcmp(name, "cydia") != 0) {
         bool cydia = false;
 
     if (strcmp(name, "cydia") != 0) {
         bool cydia = false;
+        bool _private = false;
         bool stash = false;
 
         bool stash = false;
 
+        bool repository = [[self section] isEqualToString:@"Repositories"];
+
         if (NSArray *files = [self files])
             for (NSString *file in files)
                 if (!cydia && [file isEqualToString:@"/Applications/Cydia.app"])
                     cydia = true;
         if (NSArray *files = [self files])
             for (NSString *file in files)
                 if (!cydia && [file isEqualToString:@"/Applications/Cydia.app"])
                     cydia = true;
+                else if (!_private && [file isEqualToString:@"/private"])
+                    _private = true;
                 else if (!stash && [file isEqualToString:@"/var/stash"])
                     stash = true;
 
                 else if (!stash && [file isEqualToString:@"/var/stash"])
                     stash = true;
 
-        if (cydia)
+        /* XXX: this is not sensitive enough. only some folders are valid. */
+        if (cydia && !repository)
             [warnings addObject:@"files installed into Cydia.app"];
             [warnings addObject:@"files installed into Cydia.app"];
+        if (_private)
+            [warnings addObject:@"files installed with /private/*"];
         if (stash)
             [warnings addObject:@"files installed to /var/stash"];
     }
         if (stash)
             [warnings addObject:@"files installed to /var/stash"];
     }
@@ -1736,6 +1812,13 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
     return role_;
 }
 
     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;
 - (BOOL) matches:(NSString *)text {
     if (text == nil)
         return NO;
@@ -1808,7 +1891,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
             return NSOrderedDescending;
     }
 
             return NSOrderedDescending;
     }
 
-    return [lhs compare:rhs options:CompareOptions_];
+    return [lhs compare:rhs options:LaxCompareOptions_];
 }
 
 - (NSComparisonResult) compareBySection:(Package *)package {
 }
 
 - (NSComparisonResult) compareBySection:(Package *)package {
@@ -1820,9 +1903,8 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
     else if (lhs != NULL && rhs == NULL)
         return NSOrderedDescending;
     else if (lhs != NULL && rhs != NULL) {
     else if (lhs != NULL && rhs == NULL)
         return NSOrderedDescending;
     else if (lhs != NULL && rhs != NULL) {
-        NSComparisonResult result = [lhs compare:rhs options:CompareOptions_];
-        if (result != NSOrderedSame)
-            return result;
+        NSComparisonResult result([lhs compare:rhs options:LaxCompareOptions_]);
+        return result != NSOrderedSame ? result : [lhs compare:rhs options:ForcedCompareOptions_];
     }
 
     return NSOrderedSame;
     }
 
     return NSOrderedSame;
@@ -1942,7 +2024,7 @@ NSString *Scour(const char *field, const char *begin, const char *end) {
             return NSOrderedDescending;
     }
 
             return NSOrderedDescending;
     }
 
-    return [lhs compare:rhs options:CompareOptions_];
+    return [lhs compare:rhs options:LaxCompareOptions_];
 }
 
 - (Section *) initWithName:(NSString *)name {
 }
 
 - (Section *) initWithName:(NSString *)name {
@@ -2048,9 +2130,9 @@ static NSArray *Finishes_;
                     withObject:[NSArray arrayWithObjects:string, id, nil]
                     waitUntilDone:YES
                 ];
                     withObject:[NSArray arrayWithObjects:string, id, nil]
                     waitUntilDone:YES
                 ];
-            else if (type == "pmstatus")
+            else if (type == "pmstatus") {
                 [delegate_ setProgressTitle:string];
                 [delegate_ setProgressTitle:string];
-            else if (type == "pmconffile")
+            else if (type == "pmconffile")
                 [delegate_ setConfigurationData:string];
             else _assert(false);
         } else _assert(false);
                 [delegate_ setConfigurationData:string];
             else _assert(false);
         } else _assert(false);
@@ -2246,6 +2328,7 @@ static NSArray *Finishes_;
 
     cache_.Close();
 
 
     cache_.Close();
 
+    _trace();
     if (!cache_.Open(progress_, true)) {
         std::string error;
         if (!_error->PopMessage(error))
     if (!cache_.Open(progress_, true)) {
         std::string error;
         if (!_error->PopMessage(error))
@@ -2264,6 +2347,7 @@ static NSArray *Finishes_;
 
         return;
     }
 
         return;
     }
+    _trace();
 
     now_ = [[NSDate date] retain];
 
 
     now_ = [[NSDate date] retain];
 
@@ -2296,11 +2380,14 @@ static NSArray *Finishes_;
     }
 
     [packages_ removeAllObjects];
     }
 
     [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];
     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:)];
     [packages_ sortUsingSelector:@selector(compareByName:)];
+    _trace();
 }
 
 - (void) configure {
 }
 
 - (void) configure {
@@ -2639,9 +2726,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
-    NSString *context = [sheet context];
+    NSString *context([sheet context]);
 
 
-    if ([context isEqualToString:@"remove"])
+    if ([context isEqualToString:@"remove"]) {
         switch (button) {
             case 1:
                 [self cancel];
         switch (button) {
             case 1:
                 [self cancel];
@@ -2654,10 +2741,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             default:
                 _assert(false);
         }
             default:
                 _assert(false);
         }
-    else if ([context isEqualToString:@"unable"])
-        [self cancel];
 
 
-    [sheet dismiss];
+        [sheet dismiss];
+    } else if ([context isEqualToString:@"unable"]) {
+        [self cancel];
+        [sheet dismiss];
+    } else
+        [super alertSheet:sheet buttonClicked:button];
 }
 
 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
 }
 
 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
@@ -2768,15 +2858,23 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Cancel";
 }
 
     return @"Cancel";
 }
 
-- (NSString *) _rightButtonTitle {
+- (id) _rightButtonTitle {
+#if AlwaysReload || IgnoreInstall
+    return @"Reload";
+#else
     return issues_ == nil ? @"Confirm" : nil;
     return issues_ == nil ? @"Confirm" : nil;
+#endif
 }
 
 - (void) _leftButtonClicked {
     [self cancel];
 }
 
 }
 
 - (void) _leftButtonClicked {
     [self cancel];
 }
 
+#if !AlwaysReload
 - (void) _rightButtonClicked {
 - (void) _rightButtonClicked {
+#if IgnoreInstall
+    return [super _rightButtonClicked];
+#endif
     if (essential_ != nil)
         [essential_ popupAlertAnimated:YES];
     else {
     if (essential_ != nil)
         [essential_ popupAlertAnimated:YES];
     else {
@@ -2785,6 +2883,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [delegate_ confirm];
     }
 }
         [delegate_ confirm];
     }
 }
+#endif
 
 @end
 /* }}} */
 
 @end
 /* }}} */
@@ -2845,6 +2944,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     id delegate_;
     BOOL running_;
     SHA1SumValue springlist_;
     id delegate_;
     BOOL running_;
     SHA1SumValue springlist_;
+    SHA1SumValue notifyconf_;
     SHA1SumValue sandplate_;
     size_t received_;
     NSTimeInterval last_;
     SHA1SumValue sandplate_;
     size_t received_;
     NSTimeInterval last_;
@@ -2997,7 +3097,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
-    NSString *context = [sheet context];
+    NSString *context([sheet context]);
+
     if ([context isEqualToString:@"conffile"]) {
         FILE *input = [database_ input];
 
     if ([context isEqualToString:@"conffile"]) {
         FILE *input = [database_ input];
 
@@ -3013,9 +3114,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             default:
                 _assert(false);
         }
             default:
                 _assert(false);
         }
-    }
 
 
-    [sheet dismiss];
+        [sheet dismiss];
+    }
 }
 
 - (void) closeButtonPushed {
 }
 
 - (void) closeButtonPushed {
@@ -3063,6 +3164,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             Finish_ = 4;
     }
 
             Finish_ = 4;
     }
 
+    if (Finish_ < 4) {
+        FileFd file(NotifyConfig_, FileFd::ReadOnly);
+        MMap mmap(file, MMap::ReadOnly);
+        SHA1Summation sha1;
+        sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
+        if (!(notifyconf_ == sha1.Result()))
+            Finish_ = 4;
+    }
+
     if (Finish_ < 3) {
         FileFd file(SpringBoard_, FileFd::ReadOnly);
         MMap mmap(file, MMap::ReadOnly);
     if (Finish_ < 3) {
         FileFd file(SpringBoard_, FileFd::ReadOnly);
         MMap mmap(file, MMap::ReadOnly);
@@ -3105,9 +3215,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                     NSString *plist = [path stringByAppendingPathComponent:@"Info.plist"];
                     if (NSMutableDictionary *info = [[NSMutableDictionary alloc] initWithContentsOfFile:plist]) {
                         [info autorelease];
                     NSString *plist = [path stringByAppendingPathComponent:@"Info.plist"];
                     if (NSMutableDictionary *info = [[NSMutableDictionary alloc] initWithContentsOfFile:plist]) {
                         [info autorelease];
-                        [info setObject:path forKey:@"Path"];
-                        [info setObject:@"System" forKey:@"ApplicationType"];
-                        [system addInfoDictionary:info];
+                        if ([info objectForKey:@"CFBundleIdentifier"] != nil) {
+                            [info setObject:path forKey:@"Path"];
+                            [info setObject:@"System" forKey:@"ApplicationType"];
+                            [system addInfoDictionary:info];
+                        }
                     }
                 }
         } else goto error;
                     }
                 }
         } else goto error;
@@ -3161,6 +3273,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         sandplate_ = sha1.Result();
     }
 
         sandplate_ = sha1.Result();
     }
 
+    {
+        FileFd file(NotifyConfig_, FileFd::ReadOnly);
+        MMap mmap(file, MMap::ReadOnly);
+        SHA1Summation sha1;
+        sha1.Add(reinterpret_cast<uint8_t *>(mmap.Data()), mmap.Size());
+        notifyconf_ = sha1.Result();
+    }
+
     {
         FileFd file(SpringBoard_, FileFd::ReadOnly);
         MMap mmap(file, MMap::ReadOnly);
     {
         FileFd file(SpringBoard_, FileFd::ReadOnly);
         MMap mmap(file, MMap::ReadOnly);
@@ -3283,7 +3403,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) _setProgressTitle:(NSString *)title {
 }
 
 - (void) _setProgressTitle:(NSString *)title {
-    [status_ setText:title];
+    NSMutableArray *words([[title componentsSeparatedByString:@" "] mutableCopy]);
+    for (size_t i(0), e([words count]); i != e; ++i) {
+        NSString *word([words objectAtIndex:i]);
+        if (Package *package = [database_ packageWithName:word])
+            [words replaceObjectAtIndex:i withObject:[package name]];
+    }
+
+    [status_ setText:[words componentsJoinedByString:@" "]];
 }
 
 - (void) _setProgressPercent:(NSNumber *)percent {
 }
 
 - (void) _setProgressPercent:(NSNumber *)percent {
@@ -3754,18 +3881,22 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
-    int count = [buttons_ count];
-    _assert(count != 0);
-    _assert(button <= count + 1);
+    NSString *context([sheet context]);
 
 
-    if (count != button - 1)
-        [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
+    if ([context isEqualToString:@"modify"]) {
+        int count = [buttons_ count];
+        _assert(count != 0);
+        _assert(button <= count + 1);
 
 
-    [sheet dismiss];
+        if (count != button - 1)
+            [self _clickButtonWithName:[buttons_ objectAtIndex:(button - 1)]];
+
+        [sheet dismiss];
+    } else
+        [super alertSheet:sheet buttonClicked:button];
 }
 
 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
 }
 
 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
-    [[frame windowObject] evaluateWebScript:@"document.base.target = '_top'"];
     return [super webView:sender didFinishLoadForFrame:frame];
 }
 
     return [super webView:sender didFinishLoadForFrame:frame];
 }
 
@@ -3774,6 +3905,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [super webView:sender didClearWindowObject:window forFrame:frame];
 }
 
     [super webView:sender didClearWindowObject:window forFrame:frame];
 }
 
+#if !AlwaysReload
 - (void) _rightButtonClicked {
     /*[super _rightButtonClicked];
     return;*/
 - (void) _rightButtonClicked {
     /*[super _rightButtonClicked];
     return;*/
@@ -3793,12 +3925,13 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             buttons:buttons
             defaultButtonIndex:2
             delegate:self
             buttons:buttons
             defaultButtonIndex:2
             delegate:self
-            context:@"manage"
+            context:@"modify"
         ] autorelease]];
     }
 }
         ] autorelease]];
     }
 }
+#endif
 
 
-- (NSString *) _rightButtonTitle {
+- (id) _rightButtonTitle {
     int count = [buttons_ count];
     return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
 }
     int count = [buttons_ count];
     return count == 0 ? nil : count != 1 ? @"Modify" : [buttons_ objectAtIndex:0];
 }
@@ -3845,6 +3978,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
     }
 }
 
+- (bool) _loading {
+    return false;
+}
+
 - (void) reloadData {
     [self setPackage:[database_ packageWithName:name_]];
     [self reloadButtons];
 - (void) reloadData {
     [self setPackage:[database_ packageWithName:name_]];
     [self reloadButtons];
@@ -4347,8 +4484,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
-    NSString *context = [sheet context];
-    if ([context isEqualToString:@"source"])
+    NSString *context([sheet context]);
+
+    if ([context isEqualToString:@"source"]) {
         switch (button) {
             case 1: {
                 NSString *href = [[sheet textField] text];
         switch (button) {
             case 1: {
                 NSString *href = [[sheet textField] text];
@@ -4378,7 +4516,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                 _assert(false);
         }
 
                 _assert(false);
         }
 
-    [sheet dismiss];
+        [sheet dismiss];
+    } else if ([context isEqualToString:@"trivial"])
+        [sheet dismiss];
+    else if ([context isEqualToString:@"urlerror"])
+        [sheet dismiss];
 }
 
 - (id) initWithBook:(RVBook *)book database:(Database *)database {
 }
 
 - (id) initWithBook:(RVBook *)book database:(Database *)database {
@@ -4449,12 +4591,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         context:@"source"
     ] autorelease];
 
         context:@"source"
     ] autorelease];
 
+    [sheet setNumberOfRows:1];
+
     [sheet addTextFieldWithValue:@"http://" label:@""];
 
     UITextInputTraits *traits = [[sheet textField] textInputTraits];
     [sheet addTextFieldWithValue:@"http://" label:@""];
 
     UITextInputTraits *traits = [[sheet textField] textInputTraits];
-    [traits setAutocapitalizationType:0];
-    [traits setKeyboardType:3];
-    [traits setAutocorrectionType:1];
+    [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
+    [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
+    [traits setKeyboardType:UIKeyboardTypeURL];
+    // XXX: UIReturnKeyDone
+    [traits setReturnKeyType:UIReturnKeyNext];
 
     [sheet popupAlertAnimated:YES];
 }
 
     [sheet popupAlertAnimated:YES];
 }
@@ -4474,7 +4620,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
 }
 
     return [[list_ table] isRowDeletionEnabled] ? @"Add" : nil;
 }
 
-- (NSString *) rightButtonTitle {
+- (id) rightButtonTitle {
     return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
 }
 
     return [[list_ table] isRowDeletionEnabled] ? @"Done" : @"Edit";
 }
 
@@ -4545,7 +4691,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Packages";
 }
 
     return @"Packages";
 }
 
-- (NSString *) rightButtonTitle {
+- (id) rightButtonTitle {
     return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
 }
 
     return Role_ != nil && [Role_ isEqualToString:@"Developer"] ? nil : expert_ ? @"Expert" : @"Simple";
 }
 
@@ -4570,7 +4716,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 @implementation HomeView
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
 @implementation HomeView
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
-    [sheet dismiss];
+    NSString *context([sheet context]);
+
+    if ([context isEqualToString:@"about"])
+        [sheet dismiss];
+    else
+        [super alertSheet:sheet buttonClicked:button];
 }
 
 - (void) _leftButtonClicked {
 }
 
 - (void) _leftButtonClicked {
@@ -4626,20 +4777,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Settings";
 }
 
     return @"Settings";
 }
 
-- (NSString *) _rightButtonTitle {
+#if !AlwaysReload
+- (id) _rightButtonTitle {
     return nil;
 }
     return nil;
 }
+#endif
 
 
-@end
-/* }}} */
+- (bool) _loading {
+    return false;
+}
 
 
-@interface WebView (Cydia)
-- (void) setScriptDebugDelegate:(id)delegate;
-- (void) _setFormDelegate:(id)delegate;
-- (void) _setUIKitDelegate:(id)delegate;
-- (void) setWebMailDelegate:(id)delegate;
-- (void) _setLayoutInterval:(float)interval;
 @end
 @end
+/* }}} */
 
 /* Indirect Delegate {{{ */
 @interface IndirectDelegate : NSProxy {
 
 /* Indirect Delegate {{{ */
 @interface IndirectDelegate : NSProxy {
@@ -4677,481 +4826,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 @end
 /* }}} */
 
 @end
 /* }}} */
-/* Browser Implementation {{{ */
-@implementation BrowserView
-
-- (void) dealloc {
-    WebView *webview = [webview_ webView];
-    [webview setFrameLoadDelegate:nil];
-    [webview setResourceLoadDelegate:nil];
-    [webview setUIDelegate:nil];
-    [webview setScriptDebugDelegate:nil];
-    [webview setPolicyDelegate:nil];
-
-    [webview setDownloadDelegate:nil];
-
-    [webview _setFormDelegate:nil];
-    [webview _setUIKitDelegate:nil];
-    [webview setWebMailDelegate:nil];
-    [webview setEditingDelegate:nil];
-
-    [webview_ setDelegate:nil];
-    [webview_ setGestureDelegate:nil];
-
-    //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
-
-    [webview close];
-
-#if RecycleWebViews
-    [webview_ removeFromSuperview];
-    [Documents_ addObject:[webview_ autorelease]];
-#else
-    [webview_ release];
-#endif
 
 
-    [indirect_ setDelegate:nil];
-    [indirect_ release];
-
-    [scroller_ setDelegate:nil];
-
-    [scroller_ release];
-    [urls_ release];
-    [indicator_ release];
-    if (title_ != nil)
-        [title_ release];
-    [super dealloc];
-}
-
-- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
-    [self loadRequest:[NSURLRequest
-        requestWithURL:url
-        cachePolicy:policy
-        timeoutInterval:30.0
-    ]];
-}
-
-- (void) loadURL:(NSURL *)url {
-    [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
-}
-
-- (NSURLRequest *) _addHeadersToRequest:(NSURLRequest *)request {
-    NSMutableURLRequest *copy = [request mutableCopy];
-
-    if (Machine_ != NULL)
-        [copy addValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
-    if (UniqueID_ != nil)
-        [copy addValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
-
-    if (Role_ != nil)
-        [copy addValue:Role_ forHTTPHeaderField:@"X-Role"];
-
-    return copy;
-}
-
-- (void) loadRequest:(NSURLRequest *)request {
-    pushed_ = true;
-    [webview_ loadRequest:request];
-}
-
-- (void) reloadURL {
-    if ([urls_ count] == 0)
-        return;
-    NSURL *url = [[[urls_ lastObject] retain] autorelease];
-    [urls_ removeLastObject];
-    [self loadURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData];
-}
-
-- (WebView *) webView {
-    return [webview_ webView];
-}
-
-- (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
-    [scroller_ setContentSize:frame.size];
-}
-
-- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
-    [self view:sender didSetFrame:frame];
-}
-
-- (void) pushPage:(RVPage *)page {
-    [self setBackButtonTitle:title_];
-    [page setDelegate:delegate_];
-    [book_ pushPage:page];
-}
-
-- (BOOL) getSpecial:(NSURL *)url {
-    NSString *href([url absoluteString]);
-    NSString *scheme([[url scheme] lowercaseString]);
-
-    RVPage *page = nil;
-
-    if ([href hasPrefix:@"apptapp://package/"])
-        page = [delegate_ pageForPackage:[href substringFromIndex:18]];
-    else if ([scheme isEqualToString:@"cydia"]) {
-        page = [delegate_ pageForURL:url hasTag:NULL];
-        if (page == nil)
-            return false;
-    } else if (![scheme isEqualToString:@"apptapp"])
-        return false;
-
-    if (page != nil)
-        [self pushPage:page];
-    return true;
-}
-
-- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
-    [window setValue:delegate_ forKey:@"cydia"];
-}
-
-- (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)dictionary request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id<WebPolicyDecisionListener>)listener {
-    if (NSURL *url = [request URL]) {
-        if (![self getSpecial:url]) {
-            NSString *scheme([[url scheme] lowercaseString]);
-            if ([scheme isEqualToString:@"mailto"])
-                [delegate_ openMailToURL:url];
-            else goto use;
-        }
-
-        [listener ignore];
-    } else use:
-        [listener use];
-}
-
-- (void) webView:(WebView *)webView decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
-    if ([WebView canShowMIMEType:type])
-        [listener use];
-    else {
-        // XXX: handle more mime types!
-        [listener ignore];
-        if (frame == [webView mainFrame])
-            [UIApp openURL:[request URL]];
-    }
-}
-
-- (void) webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
-    NSURL *url([request URL]);
-
-    if (url == nil) use: {
-        [listener use];
-        return;
-    }
-
-    const NSArray *capability(reinterpret_cast<const NSArray *>(GSSystemGetCapability(kGSDisplayIdentifiersCapability)));
-
-    if (
-        [capability containsObject:@"com.apple.Maps"] && [url mapsURL] ||
-        [capability containsObject:@"com.apple.youtube"] && [url youTubeURL]
-    ) {
-      open:
-        [UIApp openURL:url];
-      ignore:
-        [listener ignore];
-        return;
-    }
-
-    int store(_not(int));
-    if (NSURL *itms = [url itmsURL:&store]) {
-        NSLog(@"itms#%@#%u#%@", url, store, itms);
-        if (
-            store == 1 && [capability containsObject:@"com.apple.MobileStore"] ||
-            store == 2 && [capability containsObject:@"com.apple.AppStore"]
-        ) {
-            url = itms;
-            goto open;
-        }
-    }
-
-    NSString *scheme([[url scheme] lowercaseString]);
-
-    if ([scheme isEqualToString:@"tel"]) {
-        // XXX: intelligence
-        goto open;
-    }
-
-    if ([scheme isEqualToString:@"mailto"]) {
-        [delegate_ openMailToURL:url];
-        goto ignore;
-    }
-
-    if ([self getSpecial:url])
-        goto ignore;
-    else if ([WebView _canHandleRequest:request])
-        goto use;
-    else if ([url isSpringboardHandledURL])
-        goto open;
-    else
-        goto use;
-}
-
-- (void) webView:(WebView *)sender setStatusText:(NSString *)text {
-    //lprintf("Status:%s\n", [text UTF8String]);
-}
-
-- (void) _pushPage {
-    if (pushed_)
-        return;
-    pushed_ = true;
-    [book_ pushPage:self];
-}
-
-- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource {
-    NSURL *url = [request URL];
-    if ([self getSpecial:url])
-        return nil;
-    [self _pushPage];
-    return [self _addHeadersToRequest:request];
-}
-
-- (WebView *) _createWebViewWithRequest:(NSURLRequest *)request pushed:(BOOL)pushed {
-    [self setBackButtonTitle:title_];
-
-    BrowserView *browser = [[[BrowserView alloc] initWithBook:book_] autorelease];
-    [browser setDelegate:delegate_];
-
-    if (pushed) {
-        [browser loadRequest:[self _addHeadersToRequest:request]];
-        [book_ pushPage:browser];
-    }
-
-    return [browser webView];
-}
-
-- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
-    return [self _createWebViewWithRequest:request pushed:(request != nil)];
-}
-
-- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features {
-    return [self _createWebViewWithRequest:request pushed:YES];
-}
-
-- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
-    if ([frame parentFrame] != nil)
-        return;
-
-    title_ = [title retain];
-    [book_ reloadTitleForPage:self];
-}
-
-- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
-    if ([frame parentFrame] != nil)
-        return;
-
-    reloading_ = false;
-    loading_ = true;
-    [indicator_ startAnimation];
-    [self reloadButtons];
-
-    if (title_ != nil) {
-        [title_ release];
-        title_ = nil;
-    }
-
-    [book_ reloadTitleForPage:self];
-
-    WebView *webview = [webview_ webView];
-    NSString *href = [webview mainFrameURL];
-    [urls_ addObject:[NSURL URLWithString:href]];
-
-    [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
-
-    CGRect webrect = [scroller_ bounds];
-    webrect.size.height = 0;
-    [webview_ setFrame:webrect];
-}
-
-- (void) _finishLoading {
-    if (!reloading_) {
-        loading_ = false;
-        [indicator_ stopAnimation];
-        [self reloadButtons];
-    }
-}
-
-- (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
-    return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
-    return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
-}
-
-- (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
-    return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
-    return [webview_ webView:sender didCommitLoadForFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
-    return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
-    if ([frame parentFrame] == nil)
-        [self _finishLoading];
-    return [webview_ webView:sender didFinishLoadForFrame:frame];
-}
-
-- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
-    if ([frame parentFrame] != nil)
-        return;
-    [self _finishLoading];
-
-    [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
-        [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
-        [[error localizedDescription] stringByAddingPercentEscapes]
-    ]]];
-}
-
-- (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary {
-#if ForSaurik
-    lprintf("Console:%s\n", [[dictionary description] UTF8String]);
-#endif
-}
-
-- (id) initWithBook:(RVBook *)book {
-    if ((self = [super initWithBook:book]) != nil) {
-        loading_ = false;
-
-        struct CGRect bounds = [self bounds];
-
-        UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:bounds] autorelease];
-        [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
-        [self addSubview:pinstripe];
-
-        scroller_ = [[UIScroller alloc] initWithFrame:bounds];
-        [self addSubview:scroller_];
-
-        [scroller_ setScrollingEnabled:YES];
-        [scroller_ setAdjustForContentSizeChange:YES];
-        [scroller_ setClipsSubviews:YES];
-        [scroller_ setAllowsRubberBanding:YES];
-        [scroller_ setScrollDecelerationFactor:0.99];
-        [scroller_ setDelegate:self];
-
-        CGRect webrect = [scroller_ bounds];
-        webrect.size.height = 0;
-
-        WebView *webview;
-
-#if RecycleWebViews
-        webview_ = [Documents_ lastObject];
-        if (webview_ != nil) {
-            webview_ = [webview_ retain];
-            webview = [webview_ webView];
-            [Documents_ removeLastObject];
-            [webview_ setFrame:webrect];
-        } else {
-#else
-        if (true) {
-#endif
-            webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
-            webview = [webview_ webView];
-
-            [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
-
-            [webview_ setAllowsMessaging:YES];
-
-            [webview_ setTilingEnabled:YES];
-            [webview_ setDrawsGrid:NO];
-            [webview_ setLogsTilingChanges:NO];
-            [webview_ setTileMinificationFilter:kCAFilterNearest];
-            [webview_ setDetectsPhoneNumbers:NO];
-            [webview_ setAutoresizes:YES];
-
-            [webview_ setViewportSize:CGSizeMake(980, -1) forDocumentTypes:0x10];
-            [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x2];
-            [webview_ setViewportSize:CGSizeMake(320, -1) forDocumentTypes:0x8];
-
-            [webview_ _setDocumentType:0x4];
-
-            [webview_ setZoomsFocusedFormControl:YES];
-            [webview_ setContentsPosition:7];
-            [webview_ setEnabledGestures:0xa];
-            [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x4];
-            [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:0x7];
-
-            [webview_ setSmoothsFonts:YES];
-
-            [webview _setUsesLoaderCache:YES];
-            [webview setGroupName:@"Cydia"];
-            //[webview _setLayoutInterval:0.5];
-        }
-
-        [webview_ setDelegate:self];
-        [webview_ setGestureDelegate:self];
-        [scroller_ addSubview:webview_];
-
-        //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
-
-        CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite];
-        indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
-        [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite];
-
-        Package *package([[Database sharedInstance] packageWithName:@"cydia"]);
-        NSString *application = package == nil ? @"Cydia" : [NSString
-            stringWithFormat:@"Cydia/%@",
-            [package installed]
-        ]; [webview setApplicationNameForUserAgent:application];
-
-        indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
-
-        [webview setFrameLoadDelegate:self];
-        [webview setResourceLoadDelegate:indirect_];
-        [webview setUIDelegate:self];
-        [webview setScriptDebugDelegate:self];
-        [webview setPolicyDelegate:self];
-
-        urls_ = [[NSMutableArray alloc] initWithCapacity:16];
-
-        [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
-        [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
-        [pinstripe setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
-    } return self;
-}
-
-- (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event {
-    [webview_ redrawScaledDocument];
-}
-
-- (void) _rightButtonClicked {
-    reloading_ = true;
-    [self reloadURL];
-}
-
-- (NSString *) _rightButtonTitle {
-    return @"Reload";
-}
-
-- (NSString *) rightButtonTitle {
-    return loading_ ? @"" : [self _rightButtonTitle];
-}
-
-- (NSString *) title {
-    return title_ == nil ? @"Loading" : title_;
-}
-
-- (NSString *) backButtonTitle {
-    return @"Browser";
-}
-
-- (void) setPageActive:(BOOL)active {
-    if (!active)
-        [indicator_ removeFromSuperview];
-    else
-        [[book_ navigationBar] addSubview:indicator_];
-}
-
-- (void) resetViewAnimated:(BOOL)animated {
-}
-
-- (void) setPushed:(bool)pushed {
-    pushed_ = pushed;
-}
-
-@end
-/* }}} */
+#include <BrowserView.m>
 
 /* Cydia Book {{{ */
 @interface CYBook : RVBook <
 
 /* Cydia Book {{{ */
 @interface CYBook : RVBook <
@@ -5429,6 +5105,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return request;
 }
 
     return request;
 }
 
+- (void) _returnPNGWithImage:(UIImage *)icon forRequest:(NSURLRequest *)request {
+    id<NSURLProtocolClient> client([self client]);
+    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];
+}
+
 - (void) startLoading {
     id<NSURLProtocolClient> client([self client]);
     NSURLRequest *request([self request]);
 - (void) startLoading {
     id<NSURLProtocolClient> client([self client]);
     NSURLRequest *request([self request]);
@@ -5457,31 +5143,32 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         Package *package([database packageWithName:path]);
         if (package == nil)
             goto fail;
         Package *package([database packageWithName:path]);
         if (package == nil)
             goto fail;
-
         UIImage *icon([package icon]);
         UIImage *icon([package icon]);
-
-        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];
+        [self _returnPNGWithImage:icon forRequest:request];
+    } else if ([command isEqualToString:@"source-icon"]) {
+        if (path == nil)
+            goto fail;
+        path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+        NSString *source(Simplify(path));
+        UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sources/%@.png", App_, source]]);
+        if (icon == nil)
+            icon = [UIImage applicationImageNamed:@"unknown.png"];
+        [self _returnPNGWithImage:icon forRequest:request];
+    } else if ([command isEqualToString:@"uikit-image"]) {
+        if (path == nil)
+            goto fail;
+        path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+        UIImage *icon(_UIImageWithName(path));
+        [self _returnPNGWithImage:icon forRequest:request];
     } else if ([command isEqualToString:@"section-icon"]) {
         if (path == nil)
             goto fail;
         path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
         NSString *section(Simplify(path));
     } else if ([command isEqualToString:@"section-icon"]) {
         if (path == nil)
             goto fail;
         path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
         NSString *section(Simplify(path));
-
         UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]);
         if (icon == nil)
             icon = [UIImage applicationImageNamed:@"unknown.png"];
         UIImage *icon([UIImage imageAtPath:[NSString stringWithFormat:@"%@/Sections/%@.png", App_, section]]);
         if (icon == nil)
             icon = [UIImage applicationImageNamed:@"unknown.png"];
-
-        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];
+        [self _returnPNGWithImage:icon forRequest:request];
     } else fail: {
         [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil]];
     }
     } else fail: {
         [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil]];
     }
@@ -5700,7 +5387,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return @"Sections";
 }
 
     return @"Sections";
 }
 
-- (NSString *) rightButtonTitle {
+- (id) rightButtonTitle {
     return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
 }
 
     return [sections_ count] == 0 ? nil : editing_ ? @"Done" : @"Edit";
 }
 
@@ -5842,7 +5529,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 
     _trace();
     }
 
     _trace();
-    [packages_ radixUsingSelector:@selector(compareForChanges) withObject:nil];
+    [packages_ radixSortUsingSelector:@selector(compareForChanges) withObject:nil];
     _trace();
 
     Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
     _trace();
 
     Section *upgradable = [[[Section alloc] initWithName:@"Available Upgrades"] autorelease];
@@ -5908,7 +5595,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     return [(CYBook *)book_ updating] ? nil : @"Refresh";
 }
 
     return [(CYBook *)book_ updating] ? nil : @"Refresh";
 }
 
-- (NSString *) rightButtonTitle {
+- (id) rightButtonTitle {
     return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
 }
 
     return upgrades_ == 0 ? nil : [NSString stringWithFormat:@"Upgrade (%u)", upgrades_];
 }
 
@@ -6045,10 +5732,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     if ((self = [super initWithBook:book]) != nil) {
         CGRect pageBounds = [book_ pageBounds];
 
     if ((self = [super initWithBook:book]) != nil) {
         CGRect pageBounds = [book_ pageBounds];
 
-        /*UIImageView *pinstripe = [[[UIImageView alloc] initWithFrame:pageBounds] autorelease];
-        [pinstripe setImage:[UIImage applicationImageNamed:@"pinstripe.png"]];
-        [self addSubview:pinstripe];*/
-
         transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
         [self addSubview:transition_];
 
         transition_ = [[UITransitionView alloc] initWithFrame:pageBounds];
         [self addSubview:transition_];
 
@@ -6101,10 +5784,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         [field_ setPaddingTop:5];
 
 
         [field_ setPaddingTop:5];
 
-        UITextInputTraits *traits = [field_ textInputTraits];
-        [traits setAutocapitalizationType:0];
-        [traits setAutocorrectionType:1];
-        [traits setReturnKeyType:6];
+        UITextInputTraits *traits([field_ textInputTraits]);
+        [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
+        [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
+        [traits setReturnKeyType:UIReturnKeySearch];
 
         CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height}};
 
 
         CGRect accrect = {{0, 6}, {6 + cnfrect.size.width + 6 + area.size.width + 6, area.size.height}};
 
@@ -6265,7 +5948,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         return;
 
     _UISwitchSlider *slider([cell control]);
         return;
 
     _UISwitchSlider *slider([cell control]);
-    // XXX: this is just weird
     BOOL value([slider value] != 0);
     NSMutableDictionary *metadata([package_ metadata]);
 
     BOOL value([slider value] != 0);
     NSMutableDictionary *metadata([package_ metadata]);
 
@@ -6274,12 +5956,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         before = [number boolValue];
     else
         before = NO;
         before = [number boolValue];
     else
         before = NO;
-    NSLog(@"%@:%@ %@:%@ : %u:%u", cell, slider, name_, key, value, before);
 
     if (value != before) {
         [metadata setObject:[NSNumber numberWithBool:value] forKey:key];
         Changed_ = true;
 
     if (value != before) {
         [metadata setObject:[NSNumber numberWithBool:value] forKey:key];
         Changed_ = true;
-        //[delegate_ performSelector:@selector(updateData) withObject:nil afterDelay:0];
         [delegate_ updateData];
     }
 }
         [delegate_ updateData];
     }
 }
@@ -6308,7 +5988,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         case 1: switch (row) {
             case 0: {
                 UIPreferencesControlTableCell *cell([[[UIPreferencesControlTableCell alloc] init] autorelease]);
         case 1: switch (row) {
             case 0: {
                 UIPreferencesControlTableCell *cell([[[UIPreferencesControlTableCell alloc] init] autorelease]);
-                [cell setTitle:@"Changes only shows upgrades to installed packages. This minimizes spam from packagers. Activate this to see upgrades to this package even when it is not installed."];
+                [cell setShowSelection:NO];
+                [cell setTitle:@"Changes only shows upgrades to installed packages so as to minimize spam from packagers. Activate this to see upgrades to this package even when it is not installed."];
                 return cell;
             }
 
                 return cell;
             }
 
@@ -6336,10 +6017,12 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [ignoredSwitch_ addTarget:self action:@selector(onIgnored:) forEvents:kUIControlEventMouseUpInside];
 
         subscribedCell_ = [[UIPreferencesControlTableCell alloc] init];
         [ignoredSwitch_ addTarget:self action:@selector(onIgnored:) forEvents:kUIControlEventMouseUpInside];
 
         subscribedCell_ = [[UIPreferencesControlTableCell alloc] init];
+        [subscribedCell_ setShowSelection:NO];
         [subscribedCell_ setTitle:@"Show All Changes"];
         [subscribedCell_ setControl:subscribedSwitch_];
 
         ignoredCell_ = [[UIPreferencesControlTableCell alloc] init];
         [subscribedCell_ setTitle:@"Show All Changes"];
         [subscribedCell_ setControl:subscribedSwitch_];
 
         ignoredCell_ = [[UIPreferencesControlTableCell alloc] init];
+        [ignoredCell_ setShowSelection:NO];
         [ignoredCell_ setTitle:@"Ignore Upgrades"];
         [ignoredCell_ setControl:ignoredSwitch_];
 
         [ignoredCell_ setTitle:@"Ignore Upgrades"];
         [ignoredCell_ setControl:ignoredSwitch_];
 
@@ -6471,7 +6154,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
             buttons:[NSArray arrayWithObjects:
                 @"Upgrade Essential",
             initWithTitle:[NSString stringWithFormat:@"%d Essential Upgrade%@", count, (count == 1 ? @"" : @"s")]
             buttons:[NSArray arrayWithObjects:
                 @"Upgrade Essential",
-                @"Upgrade Everything",
+                @"Complete Upgrade",
                 @"Ignore (Temporary)",
             nil]
             defaultButtonIndex:0
                 @"Ignore (Temporary)",
             nil]
             defaultButtonIndex:0
@@ -6490,9 +6173,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [overlay_ addSubview:hud];
     [hud show:YES];*/
 
     [overlay_ addSubview:hud];
     [hud show:YES];*/
 
-    _trace();
     [database_ reloadData];
     [database_ reloadData];
-    _trace();
 
     size_t changes(0);
 
 
     size_t changes(0);
 
@@ -6870,7 +6551,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     CGSize keysize = [UIKeyboard defaultSize];
     CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
     keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
     CGSize keysize = [UIKeyboard defaultSize];
     CGRect keyrect = {{0, [overlay_ bounds].size.height}, keysize};
     keyboard_ = [[UIKeyboard alloc] initWithFrame:keyrect];
-    [[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
+    //[[UIKeyboardImpl sharedInstance] setSoundsEnabled:(Sounds_Keyboard_ ? YES : NO)];
     [overlay_ addSubview:keyboard_];
 
     if (!bootstrap_)
     [overlay_ addSubview:keyboard_];
 
     if (!bootstrap_)
@@ -6894,8 +6575,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
 }
 
 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
-    NSString *context = [sheet context];
-    if ([context isEqualToString:@"fixhalf"])
+    NSString *context([sheet context]);
+
+    if ([context isEqualToString:@"missing"])
+        [sheet dismiss];
+    else if ([context isEqualToString:@"fixhalf"]) {
         switch (button) {
             case 1:
                 @synchronized (self) {
         switch (button) {
             case 1:
                 @synchronized (self) {
@@ -6923,7 +6607,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             default:
                 _assert(false);
         }
             default:
                 _assert(false);
         }
-    else if ([context isEqualToString:@"role"]) {
+
+        [sheet dismiss];
+    } else if ([context isEqualToString:@"role"]) {
         switch (button) {
             case 1: Role_ = @"User"; break;
             case 2: Role_ = @"Hacker"; break;
         switch (button) {
             case 1: Role_ = @"User"; break;
             case 2: Role_ = @"Hacker"; break;
@@ -6948,7 +6634,9 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             [self updateData];
         else
             [self finish];
             [self updateData];
         else
             [self finish];
-    } else if ([context isEqualToString:@"upgrade"])
+
+        [sheet dismiss];
+    } else if ([context isEqualToString:@"upgrade"]) {
         switch (button) {
             case 1:
                 @synchronized (self) {
         switch (button) {
             case 1:
                 @synchronized (self) {
@@ -6974,7 +6662,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
                 _assert(false);
         }
 
                 _assert(false);
         }
 
-    [sheet dismiss];
+        [sheet dismiss];
+    }
 }
 
 - (void) reorganize { _pooled
 }
 
 - (void) reorganize { _pooled
@@ -7009,10 +6698,15 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 #if 0
     [[[MailToView alloc] initWithView:underlay_ delegate:self url:url] autorelease];
 #else
 #if 0
     [[[MailToView alloc] initWithView:underlay_ delegate:self url:url] autorelease];
 #else
-    [UIApp openURL:url];
+    [UIApp openURL:url];// asPanel:YES];
 #endif
 }
 
 #endif
 }
 
+- (void) clearFirstResponder {
+    if (id responder = [window_ firstResponder])
+        [responder resignFirstResponder];
+}
+
 - (RVPage *) pageForPackage:(NSString *)name {
     if (Package *package = [database_ packageWithName:name]) {
         PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
 - (RVPage *) pageForPackage:(NSString *)name {
     if (Package *package = [database_ packageWithName:name]) {
         PackageView *view = [[[PackageView alloc] initWithBook:book_ database:database_] autorelease];
@@ -7037,29 +6731,39 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag {
 }
 
 - (RVPage *) pageForURL:(NSURL *)url hasTag:(int *)tag {
-    NSString *href = [url absoluteString];
-
     if (tag != NULL)
         tag = 0;
 
     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];
         return [[[AddSourceView alloc] initWithBook:book_ database:database_] autorelease];
-    else if ([href isEqualToString:@"cydia://sources"])
+    else if ([path isEqualToString:@"/storage"])
+        return [self _pageForURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"storage" ofType:@"html"]] withClass:[BrowserView class]];
+    else if ([path isEqualToString:@"/sources"])
         return [[[SourceTable alloc] initWithBook:book_ database:database_] autorelease];
         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];
         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];
 
         if (Package *package = [database_ packageWithName:name]) {
             FileTable *files = [[[FileTable alloc] initWithBook:book_ database:database_] autorelease];
@@ -7127,7 +6831,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [self setIdleTimerDisabled:YES];
 
         hud_ = [self addProgressHUD];
         [self setIdleTimerDisabled:YES];
 
         hud_ = [self addProgressHUD];
-        [hud_ setText:@"Reorganizing\n\nWill Automatically\nRestart When Done"];
+        [hud_ setText:@"Reorganizing\n\nWill Automatically\nClose When Done"];
 
         [self setStatusBarShowsProgress:YES];
 
 
         [self setStatusBarShowsProgress:YES];
 
@@ -7140,22 +6844,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         [self finish];
 }
 
         [self finish];
 }
 
-/* Web Scripting {{{ */
-+ (NSString *) webScriptNameForSelector:(SEL)selector {
-    if (selector == @selector(supports:))
-        return @"supports";
-    return nil;
-}
-
-+ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector {
-    return selector != @selector(supports:);
-}
-
-- (BOOL) supports:(NSString *)feature {
-    return [feature isEqualToString:@"window.open"];
-}
-/* }}} */
-
 - (void) showKeyboard:(BOOL)show {
     CGSize keysize = [UIKeyboard defaultSize];
     CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
 - (void) showKeyboard:(BOOL)show {
     CGSize keysize = [UIKeyboard defaultSize];
     CGRect keydown = {{0, [overlay_ bounds].size.height}, keysize};
@@ -7243,7 +6931,31 @@ id Dealloc_(id self, SEL selector) {
 }*/
 
 int main(int argc, char *argv[]) { _pooled
 }*/
 
 int main(int argc, char *argv[]) { _pooled
-    bootstrap_ = argc > 1 && strcmp(argv[1], "--bootstrap") == 0;
+    class_addMethod(objc_getClass("DOMNodeList"), @selector(countByEnumeratingWithState:objects:count:), (IMP) &DOMNodeList$countByEnumeratingWithState$objects$count$, "I20@0:4^{NSFastEnumerationState}8^@12I16");
+
+    bool substrate(false);
+
+    if (argc != 0) {
+        char **args(argv);
+        int arge(1);
+
+        for (int argi(1); argi != argc; ++argi)
+            if (strcmp(argv[argi], "--") == 0) {
+                arge = argi;
+                argv[argi] = argv[0];
+                argv += argi;
+                argc -= argi;
+                break;
+            }
+
+        for (int argi(1); argi != arge; ++argi)
+            if (strcmp(args[argi], "--bootstrap") == 0)
+                bootstrap_ = true;
+            else if (strcmp(args[argi], "--substrate") == 0)
+                substrate = true;
+            else
+                fprintf(stderr, "unknown argument: %s\n", args[argi]);
+    }
 
     App_ = [[NSBundle mainBundle] bundlePath];
     Home_ = NSHomeDirectory();
 
     App_ = [[NSBundle mainBundle] bundlePath];
     Home_ = NSHomeDirectory();
@@ -7259,10 +6971,12 @@ int main(int argc, char *argv[]) { _pooled
     setuid(0);
     setgid(0);
 
     setuid(0);
     setgid(0);
 
+#if 1 /* XXX: this costs 1.4s of startup performance */
     if (unlink("/var/cache/apt/pkgcache.bin") == -1)
         _assert(errno == ENOENT);
     if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
         _assert(errno == ENOENT);
     if (unlink("/var/cache/apt/pkgcache.bin") == -1)
         _assert(errno == ENOENT);
     if (unlink("/var/cache/apt/srcpkgcache.bin") == -1)
         _assert(errno == ENOENT);
+#endif
 
     /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
     alloc_ = alloc->method_imp;
 
     /*Method alloc = class_getClassMethod([NSObject class], @selector(alloc));
     alloc_ = alloc->method_imp;
@@ -7293,9 +7007,20 @@ int main(int argc, char *argv[]) { _pooled
 
     UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier];
 
 
     UniqueID_ = [[UIDevice currentDevice] uniqueIdentifier];
 
+    if (NSDictionary *system = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"])
+        Build_ = [system objectForKey:@"ProductBuildVersion"];
+
     /*AddPreferences(@"/Applications/Preferences.app/Settings-iPhone.plist");
     AddPreferences(@"/Applications/Preferences.app/Settings-iPod.plist");*/
 
     /*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];
+
     if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
         Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
     else {
     if ((Metadata_ = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/lib/cydia/metadata.plist"]) == NULL)
         Metadata_ = [[NSMutableDictionary alloc] initWithCapacity:2];
     else {
@@ -7328,8 +7053,10 @@ int main(int argc, char *argv[]) { _pooled
     Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
 #endif
 
     Documents_ = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
 #endif
 
-    if (access("/Library/MobileSubstrate/MobileSubstrate.dylib", F_OK) == 0)
-        dlopen("/Library/MobileSubstrate/MobileSubstrate.dylib", RTLD_LAZY | RTLD_GLOBAL);
+    if (substrate && access("/Applications/WinterBoard.app/WinterBoard.dylib", F_OK) == 0)
+        dlopen("/Applications/WinterBoard.app/WinterBoard.dylib", RTLD_LAZY | RTLD_GLOBAL);
+    /*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)
         system("/usr/libexec/cydia/firmware.sh");
 
     if (access("/User", F_OK) != 0)
         system("/usr/libexec/cydia/firmware.sh");