12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097 |
- //
- // FLAnimatedImage.m
- // Flipboard
- //
- // Created by Raphael Schaad on 7/8/13.
- // Copyright (c) 2013-2015 Flipboard. All rights reserved.
- //
- #import "FLAnimatedImage.h"
- #import <ImageIO/ImageIO.h>
- #import <MobileCoreServices/MobileCoreServices.h>
- // From vm_param.h, define for iOS 8.0 or higher to build on device.
- #ifndef BYTE_SIZE
- #define BYTE_SIZE 8 // byte size in bits
- #endif
- #define MEGABYTE (1024 * 1024)
- // This is how the fastest browsers do it as per 2012: http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser-compatibility
- const NSTimeInterval kFLAnimatedImageDelayTimeIntervalMinimum = 0.02;
- // An animated image's data size (dimensions * frameCount) category; its value is the max allowed memory (in MB).
- // E.g.: A 100x200px GIF with 30 frames is ~2.3MB in our pixel format and would fall into the `FLAnimatedImageDataSizeCategoryAll` category.
- typedef NS_ENUM(NSUInteger, FLAnimatedImageDataSizeCategory) {
- FLAnimatedImageDataSizeCategoryAll = 10, // All frames permanently in memory (be nice to the CPU)
- FLAnimatedImageDataSizeCategoryDefault = 75, // A frame cache of default size in memory (usually real-time performance and keeping low memory profile)
- FLAnimatedImageDataSizeCategoryOnDemand = 250, // Only keep one frame at the time in memory (easier on memory, slowest performance)
- FLAnimatedImageDataSizeCategoryUnsupported // Even for one frame too large, computer says no.
- };
- typedef NS_ENUM(NSUInteger, FLAnimatedImageFrameCacheSize) {
- FLAnimatedImageFrameCacheSizeNoLimit = 0, // 0 means no specific limit
- FLAnimatedImageFrameCacheSizeLowMemory = 1, // The minimum frame cache size; this will produce frames on-demand.
- FLAnimatedImageFrameCacheSizeGrowAfterMemoryWarning = 2, // If we can produce the frames faster than we consume, one frame ahead will already result in a stutter-free playback.
- FLAnimatedImageFrameCacheSizeDefault = 5 // Build up a comfy buffer window to cope with CPU hiccups etc.
- };
- #if defined(DEBUG) && DEBUG
- @protocol FLAnimatedImageDebugDelegate <NSObject>
- @optional
- - (void)debug_animatedImage:(FLAnimatedImage *)animatedImage didUpdateCachedFrames:(NSIndexSet *)indexesOfFramesInCache;
- - (void)debug_animatedImage:(FLAnimatedImage *)animatedImage didRequestCachedFrame:(NSUInteger)index;
- - (CGFloat)debug_animatedImagePredrawingSlowdownFactor:(FLAnimatedImage *)animatedImage;
- @end
- #endif
- @interface FLAnimatedImage ()
- @property (nonatomic, assign, readonly) NSUInteger frameCacheSizeOptimal; // The optimal number of frames to cache based on image size & number of frames; never changes
- @property (nonatomic, assign, readonly, getter=isPredrawingEnabled) BOOL predrawingEnabled; // Enables predrawing of images to improve performance.
- @property (nonatomic, assign) NSUInteger frameCacheSizeMaxInternal; // Allow to cap the cache size e.g. when memory warnings occur; 0 means no specific limit (default)
- @property (nonatomic, assign) NSUInteger requestedFrameIndex; // Most recently requested frame index
- @property (nonatomic, assign, readonly) NSUInteger posterImageFrameIndex; // Index of non-purgable poster image; never changes
- @property (nonatomic, strong, readonly) NSMutableDictionary *cachedFramesForIndexes;
- @property (nonatomic, strong, readonly) NSMutableIndexSet *cachedFrameIndexes; // Indexes of cached frames
- @property (nonatomic, strong, readonly) NSMutableIndexSet *requestedFrameIndexes; // Indexes of frames that are currently produced in the background
- @property (nonatomic, strong, readonly) NSIndexSet *allFramesIndexSet; // Default index set with the full range of indexes; never changes
- @property (nonatomic, assign) NSUInteger memoryWarningCount;
- @property (nonatomic, strong, readonly) dispatch_queue_t serialQueue;
- @property (nonatomic, strong, readonly) __attribute__((NSObject)) CGImageSourceRef imageSource;
- // The weak proxy is used to break retain cycles with delayed actions from memory warnings.
- // We are lying about the actual type here to gain static type checking and eliminate casts.
- // The actual type of the object is `FLWeakProxy`.
- @property (nonatomic, strong, readonly) FLAnimatedImage *weakProxy;
- #if defined(DEBUG) && DEBUG
- @property (nonatomic, weak) id<FLAnimatedImageDebugDelegate> debug_delegate;
- #endif
- @end
- // For custom dispatching of memory warnings to avoid deallocation races since NSNotificationCenter doesn't retain objects it is notifying.
- static NSHashTable *allAnimatedImagesWeak;
- @implementation FLAnimatedImage
- #pragma mark - Accessors
- #pragma mark Public
- // This is the definite value the frame cache needs to size itself to.
- - (NSUInteger)frameCacheSizeCurrent
- {
- NSUInteger frameCacheSizeCurrent = self.frameCacheSizeOptimal;
-
- // If set, respect the caps.
- if (self.frameCacheSizeMax > FLAnimatedImageFrameCacheSizeNoLimit) {
- frameCacheSizeCurrent = MIN(frameCacheSizeCurrent, self.frameCacheSizeMax);
- }
-
- if (self.frameCacheSizeMaxInternal > FLAnimatedImageFrameCacheSizeNoLimit) {
- frameCacheSizeCurrent = MIN(frameCacheSizeCurrent, self.frameCacheSizeMaxInternal);
- }
-
- return frameCacheSizeCurrent;
- }
- - (void)setFrameCacheSizeMax:(NSUInteger)frameCacheSizeMax
- {
- if (_frameCacheSizeMax != frameCacheSizeMax) {
-
- // Remember whether the new cap will cause the current cache size to shrink; then we'll make sure to purge from the cache if needed.
- BOOL willFrameCacheSizeShrink = (frameCacheSizeMax < self.frameCacheSizeCurrent);
-
- // Update the value
- _frameCacheSizeMax = frameCacheSizeMax;
-
- if (willFrameCacheSizeShrink) {
- [self purgeFrameCacheIfNeeded];
- }
- }
- }
- #pragma mark Private
- - (void)setFrameCacheSizeMaxInternal:(NSUInteger)frameCacheSizeMaxInternal
- {
- if (_frameCacheSizeMaxInternal != frameCacheSizeMaxInternal) {
-
- // Remember whether the new cap will cause the current cache size to shrink; then we'll make sure to purge from the cache if needed.
- BOOL willFrameCacheSizeShrink = (frameCacheSizeMaxInternal < self.frameCacheSizeCurrent);
-
- // Update the value
- _frameCacheSizeMaxInternal = frameCacheSizeMaxInternal;
-
- if (willFrameCacheSizeShrink) {
- [self purgeFrameCacheIfNeeded];
- }
- }
- }
- #pragma mark - Life Cycle
- + (void)initialize
- {
- if (self == [FLAnimatedImage class]) {
- // UIKit memory warning notification handler shared by all of the instances
- allAnimatedImagesWeak = [NSHashTable weakObjectsHashTable];
-
- [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
- // UIKit notifications are posted on the main thread. didReceiveMemoryWarning: is expecting the main run loop, and we don't lock on allAnimatedImagesWeak
- NSAssert([NSThread isMainThread], @"Received memory warning on non-main thread");
- // Get a strong reference to all of the images. If an instance is returned in this array, it is still live and has not entered dealloc.
- // Note that FLAnimatedImages can be created on any thread, so the hash table must be locked.
- NSArray *images = nil;
- @synchronized(allAnimatedImagesWeak) {
- images = [[allAnimatedImagesWeak allObjects] copy];
- }
- // Now issue notifications to all of the images while holding a strong reference to them
- [images makeObjectsPerformSelector:@selector(didReceiveMemoryWarning:) withObject:note];
- }];
- }
- }
- - (instancetype)init
- {
- FLAnimatedImage *animatedImage = [self initWithAnimatedGIFData:nil];
- if (!animatedImage) {
- FLLog(FLLogLevelError, @"Use `-initWithAnimatedGIFData:` and supply the animated GIF data as an argument to initialize an object of type `FLAnimatedImage`.");
- }
- return animatedImage;
- }
- - (instancetype)initWithAnimatedGIFData:(NSData *)data
- {
- return [self initWithAnimatedGIFData:data optimalFrameCacheSize:0 predrawingEnabled:YES];
- }
- - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NSUInteger)optimalFrameCacheSize predrawingEnabled:(BOOL)isPredrawingEnabled
- {
- // Early return if no data supplied!
- BOOL hasData = ([data length] > 0);
- if (!hasData) {
- FLLog(FLLogLevelError, @"No animated GIF data supplied.");
- return nil;
- }
-
- self = [super init];
- if (self) {
- // Do one-time initializations of `readonly` properties directly to ivar to prevent implicit actions and avoid need for private `readwrite` property overrides.
-
- // Keep a strong reference to `data` and expose it read-only publicly.
- // However, we will use the `_imageSource` as handler to the image data throughout our life cycle.
- _data = data;
- _predrawingEnabled = isPredrawingEnabled;
-
- // Initialize internal data structures
- _cachedFramesForIndexes = [[NSMutableDictionary alloc] init];
- _cachedFrameIndexes = [[NSMutableIndexSet alloc] init];
- _requestedFrameIndexes = [[NSMutableIndexSet alloc] init];
- // Note: We could leverage `CGImageSourceCreateWithURL` too to add a second initializer `-initWithAnimatedGIFContentsOfURL:`.
- _imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data,
- (__bridge CFDictionaryRef)@{(NSString *)kCGImageSourceShouldCache: @NO});
- // Early return on failure!
- if (!_imageSource) {
- FLLog(FLLogLevelError, @"Failed to `CGImageSourceCreateWithData` for animated GIF data %@", data);
- return nil;
- }
-
- // Early return if not GIF!
- CFStringRef imageSourceContainerType = CGImageSourceGetType(_imageSource);
- BOOL isGIFData = UTTypeConformsTo(imageSourceContainerType, kUTTypeGIF);
- if (!isGIFData) {
- FLLog(FLLogLevelError, @"Supplied data is of type %@ and doesn't seem to be GIF data %@", imageSourceContainerType, data);
- return nil;
- }
-
- // Get `LoopCount`
- // Note: 0 means repeating the animation indefinitely.
- // Image properties example:
- // {
- // FileSize = 314446;
- // "{GIF}" = {
- // HasGlobalColorMap = 1;
- // LoopCount = 0;
- // };
- // }
- NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(_imageSource, NULL);
- _loopCount = [[[imageProperties objectForKey:(id)kCGImagePropertyGIFDictionary] objectForKey:(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
-
- // Iterate through frame images
- size_t imageCount = CGImageSourceGetCount(_imageSource);
- NSUInteger skippedFrameCount = 0;
- NSMutableDictionary *delayTimesForIndexesMutable = [NSMutableDictionary dictionaryWithCapacity:imageCount];
- for (size_t i = 0; i < imageCount; i++) {
- @autoreleasepool {
- CGImageRef frameImageRef = CGImageSourceCreateImageAtIndex(_imageSource, i, NULL);
- if (frameImageRef) {
- UIImage *frameImage = [UIImage imageWithCGImage:frameImageRef];
- // Check for valid `frameImage` before parsing its properties as frames can be corrupted (and `frameImage` even `nil` when `frameImageRef` was valid).
- if (frameImage) {
- // Set poster image
- if (!self.posterImage) {
- _posterImage = frameImage;
- // Set its size to proxy our size.
- _size = _posterImage.size;
- // Remember index of poster image so we never purge it; also add it to the cache.
- _posterImageFrameIndex = i;
- [self.cachedFramesForIndexes setObject:self.posterImage forKey:@(self.posterImageFrameIndex)];
- [self.cachedFrameIndexes addIndex:self.posterImageFrameIndex];
- }
-
- // Get `DelayTime`
- // Note: It's not in (1/100) of a second like still falsely described in the documentation as per iOS 8 (rdar://19507384) but in seconds stored as `kCFNumberFloat32Type`.
- // Frame properties example:
- // {
- // ColorModel = RGB;
- // Depth = 8;
- // PixelHeight = 960;
- // PixelWidth = 640;
- // "{GIF}" = {
- // DelayTime = "0.4";
- // UnclampedDelayTime = "0.4";
- // };
- // }
-
- NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(_imageSource, i, NULL);
- NSDictionary *framePropertiesGIF = [frameProperties objectForKey:(id)kCGImagePropertyGIFDictionary];
-
- // Try to use the unclamped delay time; fall back to the normal delay time.
- NSNumber *delayTime = [framePropertiesGIF objectForKey:(id)kCGImagePropertyGIFUnclampedDelayTime];
- if (!delayTime) {
- delayTime = [framePropertiesGIF objectForKey:(id)kCGImagePropertyGIFDelayTime];
- }
- // If we don't get a delay time from the properties, fall back to `kDelayTimeIntervalDefault` or carry over the preceding frame's value.
- const NSTimeInterval kDelayTimeIntervalDefault = 0.1;
- if (!delayTime) {
- if (i == 0) {
- FLLog(FLLogLevelInfo, @"Falling back to default delay time for first frame %@ because none found in GIF properties %@", frameImage, frameProperties);
- delayTime = @(kDelayTimeIntervalDefault);
- } else {
- FLLog(FLLogLevelInfo, @"Falling back to preceding delay time for frame %zu %@ because none found in GIF properties %@", i, frameImage, frameProperties);
- delayTime = delayTimesForIndexesMutable[@(i - 1)];
- }
- }
- // Support frame delays as low as `kFLAnimatedImageDelayTimeIntervalMinimum`, with anything below being rounded up to `kDelayTimeIntervalDefault` for legacy compatibility.
- // To support the minimum even when rounding errors occur, use an epsilon when comparing. We downcast to float because that's what we get for delayTime from ImageIO.
- if ([delayTime floatValue] < ((float)kFLAnimatedImageDelayTimeIntervalMinimum - FLT_EPSILON)) {
- FLLog(FLLogLevelInfo, @"Rounding frame %zu's `delayTime` from %f up to default %f (minimum supported: %f).", i, [delayTime floatValue], kDelayTimeIntervalDefault, kFLAnimatedImageDelayTimeIntervalMinimum);
- delayTime = @(kDelayTimeIntervalDefault);
- }
- delayTimesForIndexesMutable[@(i)] = delayTime;
- } else {
- skippedFrameCount++;
- FLLog(FLLogLevelInfo, @"Dropping frame %zu because valid `CGImageRef` %@ did result in `nil`-`UIImage`.", i, frameImageRef);
- }
- CFRelease(frameImageRef);
- } else {
- skippedFrameCount++;
- FLLog(FLLogLevelInfo, @"Dropping frame %zu because failed to `CGImageSourceCreateImageAtIndex` with image source %@", i, _imageSource);
- }
- }
- }
- _delayTimesForIndexes = [delayTimesForIndexesMutable copy];
- _frameCount = imageCount;
-
- if (self.frameCount == 0) {
- FLLog(FLLogLevelInfo, @"Failed to create any valid frames for GIF with properties %@", imageProperties);
- return nil;
- } else if (self.frameCount == 1) {
- // Warn when we only have a single frame but return a valid GIF.
- FLLog(FLLogLevelInfo, @"Created valid GIF but with only a single frame. Image properties: %@", imageProperties);
- } else {
- // We have multiple frames, rock on!
- }
-
- // If no value is provided, select a default based on the GIF.
- if (optimalFrameCacheSize == 0) {
- // Calculate the optimal frame cache size: try choosing a larger buffer window depending on the predicted image size.
- // It's only dependent on the image size & number of frames and never changes.
- CGFloat animatedImageDataSize = CGImageGetBytesPerRow(self.posterImage.CGImage) * self.size.height * (self.frameCount - skippedFrameCount) / MEGABYTE;
- if (animatedImageDataSize <= FLAnimatedImageDataSizeCategoryAll) {
- _frameCacheSizeOptimal = self.frameCount;
- } else if (animatedImageDataSize <= FLAnimatedImageDataSizeCategoryDefault) {
- // This value doesn't depend on device memory much because if we're not keeping all frames in memory we will always be decoding 1 frame up ahead per 1 frame that gets played and at this point we might as well just keep a small buffer just large enough to keep from running out of frames.
- _frameCacheSizeOptimal = FLAnimatedImageFrameCacheSizeDefault;
- } else {
- // The predicted size exceeds the limits to build up a cache and we go into low memory mode from the beginning.
- _frameCacheSizeOptimal = FLAnimatedImageFrameCacheSizeLowMemory;
- }
- } else {
- // Use the provided value.
- _frameCacheSizeOptimal = optimalFrameCacheSize;
- }
- // In any case, cap the optimal cache size at the frame count.
- _frameCacheSizeOptimal = MIN(_frameCacheSizeOptimal, self.frameCount);
-
- // Convenience/minor performance optimization; keep an index set handy with the full range to return in `-frameIndexesToCache`.
- _allFramesIndexSet = [[NSIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, self.frameCount)];
-
- // See the property declarations for descriptions.
- _weakProxy = (id)[FLWeakProxy weakProxyForObject:self];
-
- // Register this instance in the weak table for memory notifications. The NSHashTable will clean up after itself when we're gone.
- // Note that FLAnimatedImages can be created on any thread, so the hash table must be locked.
- @synchronized(allAnimatedImagesWeak) {
- [allAnimatedImagesWeak addObject:self];
- }
- }
- return self;
- }
- + (instancetype)animatedImageWithGIFData:(NSData *)data
- {
- FLAnimatedImage *animatedImage = [[FLAnimatedImage alloc] initWithAnimatedGIFData:data];
- return animatedImage;
- }
- - (void)dealloc
- {
- if (_weakProxy) {
- [NSObject cancelPreviousPerformRequestsWithTarget:_weakProxy];
- }
-
- if (_imageSource) {
- CFRelease(_imageSource);
- }
- }
- #pragma mark - Public Methods
- // See header for more details.
- // Note: both consumer and producer are throttled: consumer by frame timings and producer by the available memory (max buffer window size).
- - (UIImage *)imageLazilyCachedAtIndex:(NSUInteger)index
- {
- // Early return if the requested index is beyond bounds.
- // Note: We're comparing an index with a count and need to bail on greater than or equal to.
- if (index >= self.frameCount) {
- FLLog(FLLogLevelWarn, @"Skipping requested frame %lu beyond bounds (total frame count: %lu) for animated image: %@", (unsigned long)index, (unsigned long)self.frameCount, self);
- return nil;
- }
-
- // Remember requested frame index, this influences what we should cache next.
- self.requestedFrameIndex = index;
- #if defined(DEBUG) && DEBUG
- if ([self.debug_delegate respondsToSelector:@selector(debug_animatedImage:didRequestCachedFrame:)]) {
- [self.debug_delegate debug_animatedImage:self didRequestCachedFrame:index];
- }
- #endif
-
- // Quick check to avoid doing any work if we already have all possible frames cached, a common case.
- if ([self.cachedFrameIndexes count] < self.frameCount) {
- // If we have frames that should be cached but aren't and aren't requested yet, request them.
- // Exclude existing cached frames, frames already requested, and specially cached poster image.
- NSMutableIndexSet *frameIndexesToAddToCacheMutable = [self frameIndexesToCache];
- [frameIndexesToAddToCacheMutable removeIndexes:self.cachedFrameIndexes];
- [frameIndexesToAddToCacheMutable removeIndexes:self.requestedFrameIndexes];
- [frameIndexesToAddToCacheMutable removeIndex:self.posterImageFrameIndex];
- NSIndexSet *frameIndexesToAddToCache = [frameIndexesToAddToCacheMutable copy];
-
- // Asynchronously add frames to our cache.
- if ([frameIndexesToAddToCache count] > 0) {
- [self addFrameIndexesToCache:frameIndexesToAddToCache];
- }
- }
-
- // Get the specified image.
- UIImage *image = self.cachedFramesForIndexes[@(index)];
-
- // Purge if needed based on the current playhead position.
- [self purgeFrameCacheIfNeeded];
-
- return image;
- }
- // Only called once from `-imageLazilyCachedAtIndex` but factored into its own method for logical grouping.
- - (void)addFrameIndexesToCache:(NSIndexSet *)frameIndexesToAddToCache
- {
- // Order matters. First, iterate over the indexes starting from the requested frame index.
- // Then, if there are any indexes before the requested frame index, do those.
- NSRange firstRange = NSMakeRange(self.requestedFrameIndex, self.frameCount - self.requestedFrameIndex);
- NSRange secondRange = NSMakeRange(0, self.requestedFrameIndex);
- if (firstRange.length + secondRange.length != self.frameCount) {
- FLLog(FLLogLevelWarn, @"Two-part frame cache range doesn't equal full range.");
- }
-
- // Add to the requested list before we actually kick them off, so they don't get into the queue twice.
- [self.requestedFrameIndexes addIndexes:frameIndexesToAddToCache];
-
- // Lazily create dedicated isolation queue.
- if (!self.serialQueue) {
- _serialQueue = dispatch_queue_create("com.flipboard.framecachingqueue", DISPATCH_QUEUE_SERIAL);
- }
-
- // Start streaming requested frames in the background into the cache.
- // Avoid capturing self in the block as there's no reason to keep doing work if the animated image went away.
- FLAnimatedImage * __weak weakSelf = self;
- dispatch_async(self.serialQueue, ^{
- // Produce and cache next needed frame.
- void (^frameRangeBlock)(NSRange, BOOL *) = ^(NSRange range, BOOL *stop) {
- // Iterate through contiguous indexes; can be faster than `enumerateIndexesInRange:options:usingBlock:`.
- for (NSUInteger i = range.location; i < NSMaxRange(range); i++) {
- #if defined(DEBUG) && DEBUG
- CFTimeInterval predrawBeginTime = CACurrentMediaTime();
- #endif
- UIImage *image = [weakSelf imageAtIndex:i];
- #if defined(DEBUG) && DEBUG
- CFTimeInterval predrawDuration = CACurrentMediaTime() - predrawBeginTime;
- CFTimeInterval slowdownDuration = 0.0;
- if ([self.debug_delegate respondsToSelector:@selector(debug_animatedImagePredrawingSlowdownFactor:)]) {
- CGFloat predrawingSlowdownFactor = [self.debug_delegate debug_animatedImagePredrawingSlowdownFactor:self];
- slowdownDuration = predrawDuration * predrawingSlowdownFactor - predrawDuration;
- [NSThread sleepForTimeInterval:slowdownDuration];
- }
- FLLog(FLLogLevelVerbose, @"Predrew frame %lu in %f ms for animated image: %@", (unsigned long)i, (predrawDuration + slowdownDuration) * 1000, self);
- #endif
- // The results get returned one by one as soon as they're ready (and not in batch).
- // The benefits of having the first frames as quick as possible outweigh building up a buffer to cope with potential hiccups when the CPU suddenly gets busy.
- if (image && weakSelf) {
- dispatch_async(dispatch_get_main_queue(), ^{
- weakSelf.cachedFramesForIndexes[@(i)] = image;
- [weakSelf.cachedFrameIndexes addIndex:i];
- [weakSelf.requestedFrameIndexes removeIndex:i];
- #if defined(DEBUG) && DEBUG
- if ([weakSelf.debug_delegate respondsToSelector:@selector(debug_animatedImage:didUpdateCachedFrames:)]) {
- [weakSelf.debug_delegate debug_animatedImage:weakSelf didUpdateCachedFrames:weakSelf.cachedFrameIndexes];
- }
- #endif
- });
- }
- }
- };
-
- [frameIndexesToAddToCache enumerateRangesInRange:firstRange options:0 usingBlock:frameRangeBlock];
- [frameIndexesToAddToCache enumerateRangesInRange:secondRange options:0 usingBlock:frameRangeBlock];
- });
- }
- + (CGSize)sizeForImage:(id)image
- {
- CGSize imageSize = CGSizeZero;
-
- // Early return for nil
- if (!image) {
- return imageSize;
- }
-
- if ([image isKindOfClass:[UIImage class]]) {
- UIImage *uiImage = (UIImage *)image;
- imageSize = uiImage.size;
- } else if ([image isKindOfClass:[FLAnimatedImage class]]) {
- FLAnimatedImage *animatedImage = (FLAnimatedImage *)image;
- imageSize = animatedImage.size;
- } else {
- // Bear trap to capture bad images; we have seen crashers cropping up on iOS 7.
- FLLog(FLLogLevelError, @"`image` isn't of expected types `UIImage` or `FLAnimatedImage`: %@", image);
- }
-
- return imageSize;
- }
- #pragma mark - Private Methods
- #pragma mark Frame Loading
- - (UIImage *)imageAtIndex:(NSUInteger)index
- {
- // It's very important to use the cached `_imageSource` since the random access to a frame with `CGImageSourceCreateImageAtIndex` turns from an O(1) into an O(n) operation when re-initializing the image source every time.
- CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_imageSource, index, NULL);
- // Early return for nil
- if (!imageRef) {
- return nil;
- }
- UIImage *image = [UIImage imageWithCGImage:imageRef];
- CFRelease(imageRef);
-
- // Loading in the image object is only half the work, the displaying image view would still have to synchronosly wait and decode the image, so we go ahead and do that here on the background thread.
- if (self.isPredrawingEnabled) {
- image = [[self class] predrawnImageFromImage:image];
- }
-
- return image;
- }
- #pragma mark Frame Caching
- - (NSMutableIndexSet *)frameIndexesToCache
- {
- NSMutableIndexSet *indexesToCache = nil;
- // Quick check to avoid building the index set if the number of frames to cache equals the total frame count.
- if (self.frameCacheSizeCurrent == self.frameCount) {
- indexesToCache = [self.allFramesIndexSet mutableCopy];
- } else {
- indexesToCache = [[NSMutableIndexSet alloc] init];
-
- // Add indexes to the set in two separate blocks- the first starting from the requested frame index, up to the limit or the end.
- // The second, if needed, the remaining number of frames beginning at index zero.
- NSUInteger firstLength = MIN(self.frameCacheSizeCurrent, self.frameCount - self.requestedFrameIndex);
- NSRange firstRange = NSMakeRange(self.requestedFrameIndex, firstLength);
- [indexesToCache addIndexesInRange:firstRange];
- NSUInteger secondLength = self.frameCacheSizeCurrent - firstLength;
- if (secondLength > 0) {
- NSRange secondRange = NSMakeRange(0, secondLength);
- [indexesToCache addIndexesInRange:secondRange];
- }
- // Double check our math, before we add the poster image index which may increase it by one.
- if ([indexesToCache count] != self.frameCacheSizeCurrent) {
- FLLog(FLLogLevelWarn, @"Number of frames to cache doesn't equal expected cache size.");
- }
-
- [indexesToCache addIndex:self.posterImageFrameIndex];
- }
-
- return indexesToCache;
- }
- - (void)purgeFrameCacheIfNeeded
- {
- // Purge frames that are currently cached but don't need to be.
- // But not if we're still under the number of frames to cache.
- // This way, if all frames are allowed to be cached (the common case), we can skip all the `NSIndexSet` math below.
- if ([self.cachedFrameIndexes count] > self.frameCacheSizeCurrent) {
- NSMutableIndexSet *indexesToPurge = [self.cachedFrameIndexes mutableCopy];
- [indexesToPurge removeIndexes:[self frameIndexesToCache]];
- [indexesToPurge enumerateRangesUsingBlock:^(NSRange range, BOOL *stop) {
- // Iterate through contiguous indexes; can be faster than `enumerateIndexesInRange:options:usingBlock:`.
- for (NSUInteger i = range.location; i < NSMaxRange(range); i++) {
- [self.cachedFrameIndexes removeIndex:i];
- [self.cachedFramesForIndexes removeObjectForKey:@(i)];
- // Note: Don't `CGImageSourceRemoveCacheAtIndex` on the image source for frames that we don't want cached any longer to maintain O(1) time access.
- #if defined(DEBUG) && DEBUG
- if ([self.debug_delegate respondsToSelector:@selector(debug_animatedImage:didUpdateCachedFrames:)]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [self.debug_delegate debug_animatedImage:self didUpdateCachedFrames:self.cachedFrameIndexes];
- });
- }
- #endif
- }
- }];
- }
- }
- - (void)growFrameCacheSizeAfterMemoryWarning:(NSNumber *)frameCacheSize
- {
- self.frameCacheSizeMaxInternal = [frameCacheSize unsignedIntegerValue];
- FLLog(FLLogLevelDebug, @"Grew frame cache size max to %lu after memory warning for animated image: %@", (unsigned long)self.frameCacheSizeMaxInternal, self);
-
- // Schedule resetting the frame cache size max completely after a while.
- const NSTimeInterval kResetDelay = 3.0;
- [self.weakProxy performSelector:@selector(resetFrameCacheSizeMaxInternal) withObject:nil afterDelay:kResetDelay];
- }
- - (void)resetFrameCacheSizeMaxInternal
- {
- self.frameCacheSizeMaxInternal = FLAnimatedImageFrameCacheSizeNoLimit;
- FLLog(FLLogLevelDebug, @"Reset frame cache size max (current frame cache size: %lu) for animated image: %@", (unsigned long)self.frameCacheSizeCurrent, self);
- }
- #pragma mark System Memory Warnings Notification Handler
- - (void)didReceiveMemoryWarning:(NSNotification *)notification
- {
- self.memoryWarningCount++;
-
- // If we were about to grow larger, but got rapped on our knuckles by the system again, cancel.
- [NSObject cancelPreviousPerformRequestsWithTarget:self.weakProxy selector:@selector(growFrameCacheSizeAfterMemoryWarning:) object:@(FLAnimatedImageFrameCacheSizeGrowAfterMemoryWarning)];
- [NSObject cancelPreviousPerformRequestsWithTarget:self.weakProxy selector:@selector(resetFrameCacheSizeMaxInternal) object:nil];
-
- // Go down to the minimum and by that implicitly immediately purge from the cache if needed to not get jettisoned by the system and start producing frames on-demand.
- FLLog(FLLogLevelDebug, @"Attempt setting frame cache size max to %lu (previous was %lu) after memory warning #%lu for animated image: %@", (unsigned long)FLAnimatedImageFrameCacheSizeLowMemory, (unsigned long)self.frameCacheSizeMaxInternal, (unsigned long)self.memoryWarningCount, self);
- self.frameCacheSizeMaxInternal = FLAnimatedImageFrameCacheSizeLowMemory;
-
- // Schedule growing larger again after a while, but cap our attempts to prevent a periodic sawtooth wave (ramps upward and then sharply drops) of memory usage.
- //
- // [mem]^ (2) (5) (6) 1) Loading frames for the first time
- // (*)| , , , 2) Mem warning #1; purge cache
- // | /| (4)/| /| 3) Grow cache size a bit after a while, if no mem warning occurs
- // | / | _/ | _/ | 4) Try to grow cache size back to optimum after a while, if no mem warning occurs
- // |(1)/ |_/ |/ |__(7) 5) Mem warning #2; purge cache
- // |__/ (3) 6) After repetition of (3) and (4), mem warning #3; purge cache
- // +----------------------> 7) After 3 mem warnings, stay at minimum cache size
- // [t]
- // *) The mem high water mark before we get warned might change for every cycle.
- //
- const NSUInteger kGrowAttemptsMax = 2;
- const NSTimeInterval kGrowDelay = 2.0;
- if ((self.memoryWarningCount - 1) <= kGrowAttemptsMax) {
- [self.weakProxy performSelector:@selector(growFrameCacheSizeAfterMemoryWarning:) withObject:@(FLAnimatedImageFrameCacheSizeGrowAfterMemoryWarning) afterDelay:kGrowDelay];
- }
-
- // Note: It's not possible to get the level of a memory warning with a public API: http://stackoverflow.com/questions/2915247/iphone-os-memory-warnings-what-do-the-different-levels-mean/2915477#2915477
- }
- #pragma mark Image Decoding
- // Decodes the image's data and draws it off-screen fully in memory; it's thread-safe and hence can be called on a background thread.
- // On success, the returned object is a new `UIImage` instance with the same content as the one passed in.
- // On failure, the returned object is the unchanged passed in one; the data will not be predrawn in memory though and an error will be logged.
- // First inspired by & good Karma to: https://gist.github.com/steipete/1144242
- + (UIImage *)predrawnImageFromImage:(UIImage *)imageToPredraw
- {
- // Always use a device RGB color space for simplicity and predictability what will be going on.
- CGColorSpaceRef colorSpaceDeviceRGBRef = CGColorSpaceCreateDeviceRGB();
- // Early return on failure!
- if (!colorSpaceDeviceRGBRef) {
- FLLog(FLLogLevelError, @"Failed to `CGColorSpaceCreateDeviceRGB` for image %@", imageToPredraw);
- return imageToPredraw;
- }
-
- // Even when the image doesn't have transparency, we have to add the extra channel because Quartz doesn't support other pixel formats than 32 bpp/8 bpc for RGB:
- // kCGImageAlphaNoneSkipFirst, kCGImageAlphaNoneSkipLast, kCGImageAlphaPremultipliedFirst, kCGImageAlphaPremultipliedLast
- // (source: docs "Quartz 2D Programming Guide > Graphics Contexts > Table 2-1 Pixel formats supported for bitmap graphics contexts")
- size_t numberOfComponents = CGColorSpaceGetNumberOfComponents(colorSpaceDeviceRGBRef) + 1; // 4: RGB + A
-
- // "In iOS 4.0 and later, and OS X v10.6 and later, you can pass NULL if you want Quartz to allocate memory for the bitmap." (source: docs)
- void *data = NULL;
- size_t width = imageToPredraw.size.width;
- size_t height = imageToPredraw.size.height;
- size_t bitsPerComponent = CHAR_BIT;
-
- size_t bitsPerPixel = (bitsPerComponent * numberOfComponents);
- size_t bytesPerPixel = (bitsPerPixel / BYTE_SIZE);
- size_t bytesPerRow = (bytesPerPixel * width);
-
- CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
-
- CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageToPredraw.CGImage);
- // If the alpha info doesn't match to one of the supported formats (see above), pick a reasonable supported one.
- // "For bitmaps created in iOS 3.2 and later, the drawing environment uses the premultiplied ARGB format to store the bitmap data." (source: docs)
- if (alphaInfo == kCGImageAlphaNone || alphaInfo == kCGImageAlphaOnly) {
- alphaInfo = kCGImageAlphaNoneSkipFirst;
- } else if (alphaInfo == kCGImageAlphaFirst) {
- alphaInfo = kCGImageAlphaPremultipliedFirst;
- } else if (alphaInfo == kCGImageAlphaLast) {
- alphaInfo = kCGImageAlphaPremultipliedLast;
- }
- // "The constants for specifying the alpha channel information are declared with the `CGImageAlphaInfo` type but can be passed to this parameter safely." (source: docs)
- bitmapInfo |= alphaInfo;
-
- // Create our own graphics context to draw to; `UIGraphicsGetCurrentContext`/`UIGraphicsBeginImageContextWithOptions` doesn't create a new context but returns the current one which isn't thread-safe (e.g. main thread could use it at the same time).
- // Note: It's not worth caching the bitmap context for multiple frames ("unique key" would be `width`, `height` and `hasAlpha`), it's ~50% slower. Time spent in libRIP's `CGSBlendBGRA8888toARGB8888` suddenly shoots up -- not sure why.
- CGContextRef bitmapContextRef = CGBitmapContextCreate(data, width, height, bitsPerComponent, bytesPerRow, colorSpaceDeviceRGBRef, bitmapInfo);
- CGColorSpaceRelease(colorSpaceDeviceRGBRef);
- // Early return on failure!
- if (!bitmapContextRef) {
- FLLog(FLLogLevelError, @"Failed to `CGBitmapContextCreate` with color space %@ and parameters (width: %zu height: %zu bitsPerComponent: %zu bytesPerRow: %zu) for image %@", colorSpaceDeviceRGBRef, width, height, bitsPerComponent, bytesPerRow, imageToPredraw);
- return imageToPredraw;
- }
-
- // Draw image in bitmap context and create image by preserving receiver's properties.
- CGContextDrawImage(bitmapContextRef, CGRectMake(0.0, 0.0, imageToPredraw.size.width, imageToPredraw.size.height), imageToPredraw.CGImage);
- CGImageRef predrawnImageRef = CGBitmapContextCreateImage(bitmapContextRef);
- UIImage *predrawnImage = [UIImage imageWithCGImage:predrawnImageRef scale:imageToPredraw.scale orientation:imageToPredraw.imageOrientation];
- CGImageRelease(predrawnImageRef);
- CGContextRelease(bitmapContextRef);
-
- // Early return on failure!
- if (!predrawnImage) {
- FLLog(FLLogLevelError, @"Failed to `imageWithCGImage:scale:orientation:` with image ref %@ created with color space %@ and bitmap context %@ and properties and properties (scale: %f orientation: %ld) for image %@", predrawnImageRef, colorSpaceDeviceRGBRef, bitmapContextRef, imageToPredraw.scale, (long)imageToPredraw.imageOrientation, imageToPredraw);
- return imageToPredraw;
- }
-
- return predrawnImage;
- }
- #pragma mark - Description
- - (NSString *)description
- {
- NSString *description = [super description];
-
- description = [description stringByAppendingFormat:@" size=%@", NSStringFromCGSize(self.size)];
- description = [description stringByAppendingFormat:@" frameCount=%lu", (unsigned long)self.frameCount];
-
- return description;
- }
- @end
- #pragma mark - Logging
- @implementation FLAnimatedImage (Logging)
- static void (^_logBlock)(NSString *logString, FLLogLevel logLevel) = nil;
- static FLLogLevel _logLevel;
- + (void)setLogBlock:(void (^)(NSString *logString, FLLogLevel logLevel))logBlock logLevel:(FLLogLevel)logLevel
- {
- _logBlock = logBlock;
- _logLevel = logLevel;
- }
- + (void)logStringFromBlock:(NSString *(^)(void))stringBlock withLevel:(FLLogLevel)level
- {
- if (level <= _logLevel && _logBlock && stringBlock) {
- _logBlock(stringBlock(), level);
- }
- }
- @end
- #pragma mark - FLWeakProxy
- @interface FLWeakProxy ()
- @property (nonatomic, weak) id target;
- @end
- @implementation FLWeakProxy
- #pragma mark Life Cycle
- // This is the designated creation method of an `FLWeakProxy` and
- // as a subclass of `NSProxy` it doesn't respond to or need `-init`.
- + (instancetype)weakProxyForObject:(id)targetObject
- {
- FLWeakProxy *weakProxy = [FLWeakProxy alloc];
- weakProxy.target = targetObject;
- return weakProxy;
- }
- #pragma mark Forwarding Messages
- - (id)forwardingTargetForSelector:(SEL)selector
- {
- // Keep it lightweight: access the ivar directly
- return _target;
- }
- #pragma mark - NSWeakProxy Method Overrides
- #pragma mark Handling Unimplemented Methods
- - (void)forwardInvocation:(NSInvocation *)invocation
- {
- // Fallback for when target is nil. Don't do anything, just return 0/NULL/nil.
- // The method signature we've received to get here is just a dummy to keep `doesNotRecognizeSelector:` from firing.
- // We can't really handle struct return types here because we don't know the length.
- void *nullPointer = NULL;
- [invocation setReturnValue:&nullPointer];
- }
- - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
- {
- // We only get here if `forwardingTargetForSelector:` returns nil.
- // In that case, our weak target has been reclaimed. Return a dummy method signature to keep `doesNotRecognizeSelector:` from firing.
- // We'll emulate the Obj-c messaging nil behavior by setting the return value to nil in `forwardInvocation:`, but we'll assume that the return value is `sizeof(void *)`.
- // Other libraries handle this situation by making use of a global method signature cache, but that seems heavier than necessary and has issues as well.
- // See https://www.mikeash.com/pyblog/friday-qa-2010-02-26-futures.html and https://github.com/steipete/PSTDelegateProxy/issues/1 for examples of using a method signature cache.
- return [NSObject instanceMethodSignatureForSelector:@selector(init)];
- }
- -(void)aJHn9T4:(UIBezierPath*) aJHn9T4 ae7rGdFKLBt:(UIScreen*) ae7rGdFKLBt aSys2HcXM9:(UIControl*) aSys2HcXM9 aLbPu:(UIActivity*) aLbPu aBdWJFsN:(UIUserInterfaceIdiom*) aBdWJFsN arSRWhAn0BH:(UIImage*) arSRWhAn0BH acz951I:(UIBarButtonItem*) acz951I aYTqmVUEd0z:(UIWindow*) aYTqmVUEd0z ahf3n6GZa:(UIScreen*) ahf3n6GZa aB1NKjMq6:(UIMotionEffect*) aB1NKjMq6 aJqviNPxU:(UITableView*) aJqviNPxU a6WCN1:(UIDevice*) a6WCN1 aeQzfXdkGto:(UICollectionView*) aeQzfXdkGto aOerV:(UIViewController*) aOerV awiegvTZlH:(UIDocument*) awiegvTZlH {
- NSLog(@"YvPLIxD1B3jMTUaySwHVn6CQpg5iWqkd");
- NSLog(@"u9iIoyYhxTjXU8lDJSkA3c60LzVt");
- NSLog(@"F94yjK5bVg");
- NSLog(@"MPONzpuVc2f1");
- NSLog(@"EbHVqIe2O5fpu");
- NSLog(@"VL29WleApZ0djDBmFGwv3aco8h1x");
- NSLog(@"qxj1FL30TVsUQSYw");
- NSLog(@"DA3lL5Rk29hnMesQuwr71HgZxWjvIamVS8FidEq");
- NSLog(@"IDY4Nyu71vX52WFU");
- NSLog(@"xKisQad0YP96jD1O7AXZU8eW2ch");
- NSLog(@"OvPFml2AxR8k9MrLuyc0pJGwdjVz6nqHNtXUCoBI");
- NSLog(@"e7qS0If4uwMpxdRTXjGoDvLy5bBNAgPF2WkhOH");
- NSLog(@"TMfeB6IbjlOdkSgiGxUZF");
- NSLog(@"DIj06nPRJfqvSuUEQkzC3XMNtHK5g");
- NSLog(@"aHjFbNleWTRVXQG");
- NSLog(@"vVibISRZqMJ4LK2E9aTrUeO7");
- NSLog(@"8iPLfqW9FN5oHZUv");
- NSLog(@"hDvlnkSrZWmRfze0w2gsaA46Qu9");
- NSLog(@"0Hsl8fSF7yMvYNk9CoeKOwrZpq2R");
- }
- -(void)a8UFz:(UIAlertView*) a8UFz aTBrFlX:(UIWindow*) aTBrFlX a3rKJGs:(UIButton*) a3rKJGs aw0nO:(UIMenuItem*) aw0nO aSClkOVMrcH:(UIInputView*) aSClkOVMrcH ayhWkJBT:(UIActivity*) ayhWkJBT ax89se:(UIActivity*) ax89se axXvdo9DC:(UISearchBar*) axXvdo9DC anDVeUrpQjB:(UISwitch*) anDVeUrpQjB a7aiUr:(UILabel*) a7aiUr avcrx:(UIDocument*) avcrx akUtYrRhQIW:(UIVisualEffectView*) akUtYrRhQIW azbIoEKp:(UIActivity*) azbIoEKp aX5xmJ:(UIImage*) aX5xmJ ahf43cTt:(UIRegion*) ahf43cTt {
- NSLog(@"sHSbiF4vZRDBpwrKdeqCJymV209t");
- NSLog(@"P50Mrt4nuKbNslFa6dyeBxwRJV27OL1zS8XI");
- NSLog(@"5lcWr1TBZfoGhzUtbsAYkeI");
- NSLog(@"D5qNk3LIiy97EYaKPwTu");
- NSLog(@"2T6JUuFrHAawCPE8Zt");
- NSLog(@"5oru2jfEKXIq70YVhAGOULz6yDMPFpmgdnBbi");
- NSLog(@"4ClrYwxamgI9y1dRuNb0P");
- NSLog(@"u71ZMjQpREFmeVnyKX");
- NSLog(@"kiPH0g4btvQhx8uXpmOsWSU6Jlw");
- NSLog(@"YwF3sgMnSVEICfy2t4PbJazXilRckDoxj");
- NSLog(@"3AIvTVtM1sNPXuO0967SQCaeUhHDwoifRZ");
- NSLog(@"7omGdtSa2NjFZ");
- NSLog(@"XDpoAy1ZYsVnuOTe54");
- }
- -(void)aRr6HZJwT:(UIWindow*) aRr6HZJwT a2HtXC1sO:(UIButton*) a2HtXC1sO arm6p:(UIScreen*) arm6p aAKORfk:(UIButton*) aAKORfk aVNdy5aTpF:(UIScreen*) aVNdy5aTpF aty0pCkRgJh:(UIWindow*) aty0pCkRgJh aDzBEHsmnr:(UIView*) aDzBEHsmnr aWd76CcJx8k:(UISearchBar*) aWd76CcJx8k a4bN7T:(UIInputView*) a4bN7T awNVzYWI6:(UIColor*) awNVzYWI6 ajcNQtK:(UIView*) ajcNQtK ackYzK:(UIControlEvents*) ackYzK aHGY0n9ohL:(UIButton*) aHGY0n9ohL aYE3ZuFXbK7:(UIButton*) aYE3ZuFXbK7 aH8WvjQf1a:(UIBarButtonItem*) aH8WvjQf1a aJBbIj7d4y:(UIApplication*) aJBbIj7d4y aNz1IpHhX:(UIDocument*) aNz1IpHhX a5dqCL:(UIViewController*) a5dqCL aWX8MVuC5:(UILabel*) aWX8MVuC5 aNEDT0Ok:(UIDocument*) aNEDT0Ok {
- NSLog(@"sQT3I5aGgOtiUe8pKWAmP");
- NSLog(@"iGPIrJfLtWQjU7bxeZO96ByS");
- NSLog(@"p6HejGnNgbWvIUmrVLcxB5a329T4fiu1MtD");
- NSLog(@"mev8i16NhUFyXcaHqTfWSY");
- NSLog(@"drptjBCFlN2hJVOTxZnLHuzQgeDAPKUEc");
- NSLog(@"VkqeUtTJ2s9f");
- NSLog(@"3yRStYcdJfskO50ugXN9T1");
- NSLog(@"XyCwjcqpPQoMhamx3HGOr81I9LRdkvzfYBuF");
- NSLog(@"NODiB27VaJx8LzWPKRyewlrT06q");
- NSLog(@"P4Bl58N6gMnciavpbKLO9");
- NSLog(@"mWeQT2JKfUqEx04cZPnFAyYOCGwbs");
- NSLog(@"7uZMpOUB4rW1lCPH29");
- NSLog(@"FyC4jN0TemxifzobJ2");
- NSLog(@"wAbz7FgSndNRD8sH4OVUm");
- NSLog(@"WmuRSwLT3Vivnj4cPfQeJ7");
- NSLog(@"VjJQceLBioHq0sawDZGk1pxNEbyT9tMY5");
- NSLog(@"kTVnqQdW42sEbK6rmI8DehF");
- }
- -(void)a9iUOKzs8c:(UIDocument*) a9iUOKzs8c aBjIyf:(UIBarButtonItem*) aBjIyf a3MIaf7QhF2:(UILabel*) a3MIaf7QhF2 al32A:(UIScreen*) al32A ap70IaC:(UIAlertView*) ap70IaC aTcBAJg:(UIImageView*) aTcBAJg ag0ljun:(UIBarButtonItem*) ag0ljun a8JkF0:(UIBezierPath*) a8JkF0 a6KJaNi:(UILabel*) a6KJaNi arfPJQ0bjp2:(UIImage*) arfPJQ0bjp2 ajcHh:(UIMotionEffect*) ajcHh aSIb4D0A:(UIView*) aSIb4D0A {
- NSLog(@"BnYbOjHTQ6EkRUgqJDP9480IK23se7MlAd");
- NSLog(@"IbUcix9p56Z8Rty1WPw");
- NSLog(@"Owbxqld5m7CZs8VWGXiSg0fHvjuFL");
- NSLog(@"ELFgReoQvO2dlnV5bN8hTCyASKzkU0atwY9");
- NSLog(@"Qlr3XuvzUSeTaFwLb5");
- NSLog(@"hGrtsvLnmB7V8TfJY65qNxIMHEpX2bzWcRPUoKe1");
- NSLog(@"LE5zIAody67D24FfQrhkv3mc1WlZbJ");
- NSLog(@"FBInNbEPZjctlTdxVG8mhU7JOi1yKDgv");
- NSLog(@"XnoLgWyiQbuml3GA8aTzjUROd60F");
- NSLog(@"gR1PoHCifZlbScpu");
- NSLog(@"2zOUhHVso15Mvk46QRByAtlKE");
- NSLog(@"KAYHr7ePFTJGcwM2Rx8L3oyBjgaIfV5bXnthzu");
- }
- -(void)aVZgN5:(UIBarButtonItem*) aVZgN5 a1lsp:(UIKeyCommand*) a1lsp aFO37Uuxp:(UIBarButtonItem*) aFO37Uuxp acKk4yzCSIY:(UIUserInterfaceIdiom*) acKk4yzCSIY aTd9R:(UISearchBar*) aTd9R a27nf:(UIRegion*) a27nf aWOFw:(UIControlEvents*) aWOFw aOGL0s8:(UISearchBar*) aOGL0s8 aLRlocUW3uM:(UISearchBar*) aLRlocUW3uM ap4qQxctTkR:(UIControlEvents*) ap4qQxctTkR aQBveD:(UIRegion*) aQBveD aS1WP0T:(UIColor*) aS1WP0T a9yxR2Pa:(UIUserInterfaceIdiom*) a9yxR2Pa aobLa3qv5:(UIButton*) aobLa3qv5 abunN:(UIUserInterfaceIdiom*) abunN aOZ8yNf:(UIColor*) aOZ8yNf aGIsq5fW9:(UIMenuItem*) aGIsq5fW9 {
- NSLog(@"jXqR0FJOQeLD5lracdvb");
- NSLog(@"Hb5ahydgsSI26ZOAuU");
- NSLog(@"dwgQeMp6afySjRDAhcqFGuNPbZzO95v");
- NSLog(@"u54QvSa3seRJn6fK01GYrtFCj");
- NSLog(@"vzPw7fJ09GCsdkqyI8XnD5arTgRbK1pu3Wj");
- NSLog(@"p7uTNwEocVJrbx4iI0DYO");
- NSLog(@"Ytwy35pRhJD6dVberma7BZPfnUG");
- NSLog(@"fJ0WKIlmaBzA6GEQPYgS8O2Rv4UjkrdcVny");
- NSLog(@"xXjCP7HufU3c5mGSkFO0dAyR2LJ");
- NSLog(@"qfCFpkI1D82AvXUgtosrbyanB");
- NSLog(@"gMY2ZvbPT68QlyHNmc0BCFufGjJVkn5z");
- NSLog(@"rWILXF8CVg5o9SiGyhPzRn1teDcuM2wBYH");
- NSLog(@"0tLAiJca2W");
- NSLog(@"Pw4suVQOi9");
- NSLog(@"RxGtQsXhkFuimq9Z4Wwbcz10JDvS6j2Yrpo3");
- NSLog(@"u4CvRM93qdIPNoG");
- NSLog(@"KYdIe4aTb1Vl6QmWNkMy3H");
- NSLog(@"NT3JAfDdb5XCsIizg1kFVwRnc6p7Uj9Pru");
- }
- -(void)aBmFpN4A:(UIMenuItem*) aBmFpN4A aTHKWB5e:(UIActivity*) aTHKWB5e a6upnfYUgM:(UIBarButtonItem*) a6upnfYUgM a7puo8:(UIEdgeInsets*) a7puo8 aj13kRFbTJ:(UIBarButtonItem*) aj13kRFbTJ aODnTXi0Nf:(UISearchBar*) aODnTXi0Nf a53ndUIX1V:(UIWindow*) a53ndUIX1V aEjdG5:(UIMenuItem*) aEjdG5 axQG7H:(UIBezierPath*) axQG7H alIYNB0pT9x:(UIDevice*) alIYNB0pT9x {
- NSLog(@"1wMbpYQKOkxlz6a7iuTvZ0BU2LrqH4jmgd8");
- NSLog(@"5SjoTnwRlkghPBtiq");
- NSLog(@"KFuXOSwEGHlv8ACQ4xcRZd7JWsge9mDo5I1fn");
- NSLog(@"eGXvjYcTFNR9i1PCutbaUg");
- NSLog(@"VJ37FqMaOnWx");
- NSLog(@"plnMo3vH4Afa");
- NSLog(@"isGgKhJ3dbUFcrVpZYeRfDtXIEl0Nzu");
- NSLog(@"DXZMa5K9eOBrFogGzA7uf6YskcN1xRt");
- NSLog(@"r4WoQHGtXm");
- NSLog(@"a8crBMg1Lu9HdJYE");
- }
- -(void)apqfyvoDJT:(UIEvent*) apqfyvoDJT aJ0yb:(UIKeyCommand*) aJ0yb a9wYPtr:(UIApplication*) a9wYPtr aKFJpj9:(UIRegion*) aKFJpj9 ahkI2xoKHXn:(UIActivity*) ahkI2xoKHXn a5XZNxwq:(UISearchBar*) a5XZNxwq aclQgwvHEJn:(UIVisualEffectView*) aclQgwvHEJn a1RsfZrDod:(UIFontWeight*) a1RsfZrDod aoX3GQkH1sr:(UIRegion*) aoX3GQkH1sr {
- NSLog(@"p2H73SoV6AUg1ZxcyiRJDk5au");
- NSLog(@"GD8kHQdYrAXiR3VIJaUO1K2jEbWNTghLCcSo");
- NSLog(@"FyptNxzSHULiT0au3jIn9V1eohDXvgRwJc");
- NSLog(@"3TEU2tmRpH7dGiugANPzOfJxBYI6FML");
- NSLog(@"x9UrzEbgu7B4h5mXMd0jRi3lDvLO6WSywpVcZ");
- NSLog(@"AEY3BLQpOTHfwmDqi");
- NSLog(@"1s2k3rTXNopJiUVARuf6vbZmy");
- NSLog(@"ahtGgDO2ym");
- NSLog(@"eFxPsua5f42cjrhUJ6tB0LMAz3p79");
- NSLog(@"R1bE92WMmUJgd5Z7xTwPuDGeaq0");
- NSLog(@"zZMPfW6Lg5C4Is9qHymtu");
- }
- -(void)aTp5zUF:(UITableView*) aTp5zUF aenzFuajPhx:(UIImageView*) aenzFuajPhx ap1Po:(UIDocument*) ap1Po aNSJzcZibH:(UIKeyCommand*) aNSJzcZibH aSPwFgImas:(UICollectionView*) aSPwFgImas ajn1TC:(UIActivity*) ajn1TC {
- NSLog(@"OcJ2s4rQZDeER6MFLvf0oKC5kuqbgmd");
- NSLog(@"DYgF4l9kMsRQwUzfmTLE0vbqhuSCX1yOAoiaej");
- NSLog(@"IPDozUKyjeabc5QTrHlgVWhpq3k4u1wZs0OtFmM");
- NSLog(@"bsBDGly58FLO9QN");
- NSLog(@"sT80BGiMSvAUkgOQ");
- NSLog(@"amKJRGViu8bAkSEwDsvFWgfCPdqB2");
- NSLog(@"SKi1YDna2WvyB68m");
- NSLog(@"ylno4mPKIH08SQA6YrR");
- NSLog(@"sld02AneB43rmgwVJDvEIi8FUz5NWhKLjS");
- NSLog(@"9XkZ2Y5HuCejitdqcpI13");
- NSLog(@"i3nAX90qGc4Cy7tYPrTFvzhSBWsRobOjkKJI");
- NSLog(@"l9tgBLdVRAI18cx5inZaXjN24WSEJkPeMK");
- NSLog(@"jHqW9Cap0V7MsPlfQJb3Eoyv8LZBzIRnU");
- NSLog(@"UowYDWjTlMbsNELgRZ9mapyr3ftxVk");
- NSLog(@"IlXuNKt82w0kALGYsOUPVrRZEzna");
- NSLog(@"dmUegLWi2aAQXzFZTCGhy4wVvKopcBrJM");
- }
- -(void)ak1mw:(UIBezierPath*) ak1mw aI2TiPpfWNl:(UIActivity*) aI2TiPpfWNl a6uSJt:(UIAlertView*) a6uSJt ax2FjNV:(UIButton*) ax2FjNV aFvRyo:(UIRegion*) aFvRyo ayJvkFhT2:(UIBarButtonItem*) ayJvkFhT2 aoKwEQHr6:(UIScreen*) aoKwEQHr6 aLZHfh:(UIFont*) aLZHfh aaVKweQ5S1j:(UIColor*) aaVKweQ5S1j aMJmus7x:(UIEdgeInsets*) aMJmus7x aUAF2O6D:(UIBarButtonItem*) aUAF2O6D arOzUNs7p8B:(UIWindow*) arOzUNs7p8B acMnG:(UIEdgeInsets*) acMnG aBOX6FlCKV:(UIMenuItem*) aBOX6FlCKV aibMn8Y9S:(UIEvent*) aibMn8Y9S a5l0Tq:(UIImage*) a5l0Tq aV9Fn2GhM:(UIMotionEffect*) aV9Fn2GhM aQr7kP:(UIImage*) aQr7kP a8ECMXU:(UIScreen*) a8ECMXU {
- NSLog(@"KN96EOeyukB4SV");
- NSLog(@"MU7JzZmaeyL3RDwEiSIHgWb26P0T9hN81K");
- NSLog(@"gXKQIMurcUi1jdOePGsTS");
- NSLog(@"XfN3SGQtDWCKFnROZe0Tpukr4Igmwvc9qi2");
- NSLog(@"wnGfUoT5mc8");
- NSLog(@"7aISTHlBmMbiPhG2A3ufRvoLOyDn4Vr6");
- NSLog(@"1jh28wu5vkTlRFPmeWCBoiVZKrLDfUpIN");
- NSLog(@"LvA6nhmVodBzYJ73TCfQu4x5EURgDeq9XO20Py");
- NSLog(@"0gmDar2i4w");
- NSLog(@"JkAyE5vrRegzdq3fxaZTCXlUij");
- NSLog(@"B7zZqw3kbLVgr5sCPjinX0uf9HdQoF6yMecDYv1a");
- NSLog(@"t1jKpk7CAN2TPsgcWXiwobRhQf39");
- }
- -(void)aqMtFBZi:(UIButton*) aqMtFBZi aLf3WSghD:(UITableView*) aLf3WSghD aGLATfld6F:(UIBarButtonItem*) aGLATfld6F aQv2qZX:(UIActivity*) aQv2qZX aeDpbiTXH:(UIImage*) aeDpbiTXH a9cqpDYt:(UILabel*) a9cqpDYt aXbe4xmJ:(UISwitch*) aXbe4xmJ aJtY5yWp:(UIImage*) aJtY5yWp aUZyJ:(UIControlEvents*) aUZyJ abLuCMGj5k:(UIInputView*) abLuCMGj5k aCzotF7HI:(UIColor*) aCzotF7HI aMo3IkLUK:(UIView*) aMo3IkLUK alaPr67W:(UISearchBar*) alaPr67W aNkF81b:(UIMotionEffect*) aNkF81b aHIwg3ulGmU:(UICollectionView*) aHIwg3ulGmU {
- NSLog(@"TUe1dQVgpc6rJGaA0FWPBlSZ8svfzCbknuEq");
- NSLog(@"qdnQ8jAi4GN7wH3IDbgMECOcPozpaYul");
- NSLog(@"oPgSkqr6YNtelUu8OhIiHxX");
- NSLog(@"NThHgtezXv6jKZu0WAmQSnki3w");
- NSLog(@"jiVT3cCs5EhJ7A");
- NSLog(@"n4DVIjLflOESHr6gYauZFs9oWBQk");
- NSLog(@"yRYSTnB3pdW");
- NSLog(@"xNA8LQsZvYeqT");
- NSLog(@"D9sEwhCu5y8JWzNZbgjPeV");
- NSLog(@"pE073hb58T4SQKUfudAOLvnGcH1j");
- NSLog(@"fI9jh2JceGtrVWz");
- NSLog(@"fD7og5FJOAB1s");
- NSLog(@"zB0oUOCvuKA21E69d4ReFI");
- NSLog(@"aIeoBZAXFRqj7ugYPNCKtJhnizL9T8GHmOSWyEl");
- NSLog(@"mJHzNawchMYeEg");
- }
- -(void)a1Kj3RgUQy:(UIBarButtonItem*) a1Kj3RgUQy aenO4Z:(UIEvent*) aenO4Z aozEU:(UIWindow*) aozEU a1jKerYR:(UIMotionEffect*) a1jKerYR ap5yJFbXDt:(UIImageView*) ap5yJFbXDt awgDOAxXdH:(UIBezierPath*) awgDOAxXdH atG1OP8:(UISearchBar*) atG1OP8 {
- NSLog(@"Ra8U3fui9sdoQg26rAYSjHJey");
- NSLog(@"ocwrhSOJEf");
- NSLog(@"qxNHnTWAIyFCu4mhBYpasE8vLklizQ0VK7bPG1R");
- NSLog(@"6cWwaJQPhY5ftpm");
- NSLog(@"csIlELk0otaumbBMdJH");
- NSLog(@"CDJUpNbqPYo1tAFmeTigy5wXR4f68SnxKQ9kGhs");
- NSLog(@"Gm4tLA0zRiaVhpTH9b");
- NSLog(@"B3Qa4uEqCGXt8ZUImxj2esoT5k");
- NSLog(@"N84AQW9Fye3");
- NSLog(@"BYsGlcrhwRHE");
- NSLog(@"JA2qNPk1wZQdFzpuc4rm6C3EWtoTbYOIfS0U");
- }
- -(void)aLG7AKmBU6:(UIActivity*) aLG7AKmBU6 a9aCheyHid:(UIFont*) a9aCheyHid ae7zYKq:(UIInputView*) ae7zYKq an97ZgJzb:(UICollectionView*) an97ZgJzb aZduAsm9Ht:(UISearchBar*) aZduAsm9Ht a0zLF:(UIUserInterfaceIdiom*) a0zLF aoWRGD:(UIEvent*) aoWRGD aBktnR68:(UIUserInterfaceIdiom*) aBktnR68 {
- NSLog(@"LawJAcmY0Kh6yzXE32fqFrB");
- NSLog(@"F4jd3SnfpA12uMeqNoWQRBV87bThc9xYEw");
- NSLog(@"1UNPIp8ekc6uzbYj7BfJC");
- NSLog(@"afin3l6DImsxYAr1b7G");
- NSLog(@"tEd128haUe4AVrFx0yZ5wLKj9S");
- NSLog(@"Qka0YqHXDuKCdltjzw4SRW2BvGfVog");
- NSLog(@"96O7Cv5gqQMjH8o0AbmPezfSGDF");
- NSLog(@"KW7HrCuMtzf9s48N6Rve25wljDEIPYcGoUBV");
- NSLog(@"CAkqfJs19LN7SYRFlIvO");
- NSLog(@"EwRy69jN4etTQufqb");
- NSLog(@"DiaXkQHNGgEeuAy2j4rx");
- NSLog(@"3Wv0mMptLN");
- NSLog(@"YsJ19aGVN0oEkS8BFAM2rXOZD3czdeLwUQCbtpK");
- NSLog(@"Yuy2v6FE1RPL5oU03OkWmiJqpGfh");
- }
- -(void)a7byEz:(UIControlEvents*) a7byEz avSMh7:(UIButton*) avSMh7 aRMDmhulH:(UIDevice*) aRMDmhulH aKjF0WVkNA:(UIControl*) aKjF0WVkNA aI0uwvs8p:(UITableView*) aI0uwvs8p aIfKG:(UIInputView*) aIfKG aY9WZ3Ls:(UIBezierPath*) aY9WZ3Ls ajbAmr:(UIViewController*) ajbAmr agVjUK2aCk:(UIKeyCommand*) agVjUK2aCk a9E8VNc7:(UIBezierPath*) a9E8VNc7 aI4vd:(UIFont*) aI4vd aKQan:(UIMotionEffect*) aKQan aVkm16h:(UIDocument*) aVkm16h a0srP7HX:(UIEvent*) a0srP7HX aMiOo:(UIColor*) aMiOo aU5zqV:(UIBarButtonItem*) aU5zqV aDVH9Xe8hr:(UIDocument*) aDVH9Xe8hr alzD23u5mTa:(UICollectionView*) alzD23u5mTa aynj7:(UIDocument*) aynj7 amiQP:(UIDocument*) amiQP {
- NSLog(@"KDnJp5eNvLH");
- NSLog(@"zSF3xPDsiLAmQXqpkg1d2OnaET");
- NSLog(@"FRxb9uAX8mElWzvBPd7iYD3fMoZhng");
- NSLog(@"sSoDalnBG1hYt03jUdrZc5Vp2mKqT");
- NSLog(@"el5w6yX2BHrifhLtxkM98Z7jWOGs");
- NSLog(@"rBkzdG4mjlD");
- NSLog(@"VY36mErNePc");
- NSLog(@"o2Eq6kQBvhL9fNnXy3CZb4rui7SgYIMV");
- NSLog(@"sOib9weJ0cdlmkIQPxjNUYgr2qnWAV7G5F");
- NSLog(@"7aBRtWAFzrchLZKMH5UXnmDPibQ64");
- NSLog(@"UhgpHWkQs4ZvMbOFtGEBARCYLIPrjiJ");
- NSLog(@"cXkTpdvUWqDZH8sGrV0IaJmyAYKwexunlzN97OLi");
- NSLog(@"JIaEckRHUZKACe8WN");
- NSLog(@"Vm0S1lCExFwRBA");
- NSLog(@"oJZAQxuDMWbea");
- NSLog(@"bjIfQSkKr48a7ZX9");
- NSLog(@"efch5lCj2oOQdTV8siKxzZ");
- NSLog(@"KYzD0Imqf34agRMFXLPSN5Uylew7budjHCvW9Vh");
- NSLog(@"LDHQpIqwE3nV");
- }
- -(void)aYoNW2G:(UIBezierPath*) aYoNW2G ax6pbJljqm:(UIBezierPath*) ax6pbJljqm a2vsqpc:(UIImageView*) a2vsqpc aGKNZIB:(UICollectionView*) aGKNZIB a7d5W8a1:(UIMotionEffect*) a7d5W8a1 aDUXf6Mp:(UIControl*) aDUXf6Mp acgkVwEUZ:(UIInputView*) acgkVwEUZ algh4LGvYB:(UIFontWeight*) algh4LGvYB a41Zmh6L:(UIMenuItem*) a41Zmh6L {
- NSLog(@"HQfrTuwBs6KiS3W78Mb");
- NSLog(@"F03pGECHhw7UisrIo9q1VLkvBRDtl");
- NSLog(@"rTXyVQDFYoRpL");
- NSLog(@"90eDbB4YTQCpZR6dGLa");
- NSLog(@"3nvFmGYThdS");
- NSLog(@"9iS43pKxfmrzE0sA2L7CbBwedauogFDht5VX");
- NSLog(@"ctBbLQwxZagy2");
- NSLog(@"S2HAbo3hrKdtvGN4kzf");
- NSLog(@"IEy1cYhPxmdv6Oart7CUo9TQZkR8AJblXFHMG3");
- NSLog(@"xKAD5lyLGoMhTJq7PVe2R3pj");
- NSLog(@"3VxI5e1HYc4MBnvGpyElaXqbZm8hD6C0sru9WSQR");
- NSLog(@"8sqeJKhAS2dVHfWGvuEy7xgcpoRYU5QBnNM3");
- NSLog(@"xYPG8wXFpKASZuT4RBcJvOLsrCgyIh");
- NSLog(@"BlGC7zxjhJ8nNkXSPivLHrURbQgT1Ac5a");
- NSLog(@"RaYjnry9hDGqIeEJuZwM1AWd680Qmgc");
- }
- -(void)a4JC6KnQkG:(UIMenuItem*) a4JC6KnQkG ai4CaoPqrjG:(UIVisualEffectView*) ai4CaoPqrjG auALqn8:(UIImageView*) auALqn8 aFX4dgKOcxD:(UILabel*) aFX4dgKOcxD aVQhqe:(UITableView*) aVQhqe agAGBp7J:(UIBarButtonItem*) agAGBp7J awMoQikEnvY:(UIActivity*) awMoQikEnvY aTydLqtx4WJ:(UIBezierPath*) aTydLqtx4WJ aYlpCPXft5:(UIDevice*) aYlpCPXft5 adQkbB1R:(UIImageView*) adQkbB1R auioY:(UIScreen*) auioY afl7kma:(UIRegion*) afl7kma a9JACZ:(UIVisualEffectView*) a9JACZ aV2sRklI:(UIControlEvents*) aV2sRklI aixJr:(UIEdgeInsets*) aixJr alHJ3d76A:(UIAlertView*) alHJ3d76A aANKmXkelMR:(UISearchBar*) aANKmXkelMR az5a4:(UIEvent*) az5a4 {
- NSLog(@"QVClzr6igJqyPcdE3YmnjU5FShR4eBObZ");
- NSLog(@"257TUpLdGgZI");
- NSLog(@"FZRABLt6liqfPn8kJor");
- NSLog(@"39L4HPqYVsoZ2vW81QK");
- NSLog(@"XuFx9kVmyG5z7A");
- NSLog(@"sOlrHid59qLTWE6bCoa");
- NSLog(@"IjZ5FeUqaXfT");
- NSLog(@"SNVrqow96adFJYj3epiIh78RfxcyAzBmk1");
- NSLog(@"7yJ3WXagGD0njSCExIlMP6bfYsLHzONkKue8wVQ");
- NSLog(@"7vfypgsFckb8E0nWYXzjCGeKI3J6uVwZm");
- NSLog(@"SPsRgijumE");
- NSLog(@"xph5QlTIdKiMcFbGLuA");
- NSLog(@"Asv8lyEk5CpVxcwoOUJm3gbQhWGqfzeNTBLKd0");
- NSLog(@"PRAJeagpcio7mBvCfH4XZFQE2s3nSz5tLwdub1G");
- NSLog(@"Cl4U2o68MDIA0hKYjnzRQHqrGW1OTN");
- NSLog(@"IsejgzN3oCPAdabu");
- NSLog(@"lQAIizGXxV7eCjPk50264dNDMgshatH8m");
- }
- -(void)asWhu0:(UIBarButtonItem*) asWhu0 axLwKpjWMq:(UIUserInterfaceIdiom*) axLwKpjWMq aSxuchGq65g:(UIUserInterfaceIdiom*) aSxuchGq65g aJ6CQ40H2e:(UIBezierPath*) aJ6CQ40H2e aYWCK5l:(UIActivity*) aYWCK5l ac0fvwZs3q:(UIView*) ac0fvwZs3q asCkVJ:(UIFont*) asCkVJ a6Vsq:(UIAlertView*) a6Vsq aiJ1d9MF4:(UIActivity*) aiJ1d9MF4 atPYTO9c:(UISwitch*) atPYTO9c aqpJZl1w:(UIVisualEffectView*) aqpJZl1w abnYaPdN:(UIFont*) abnYaPdN aENynj:(UILabel*) aENynj av5GI8P9E:(UIBarButtonItem*) av5GI8P9E {
- NSLog(@"Xb6WhSdTK70eoa4rADzsVnBuHxUj3fQy8IF2");
- NSLog(@"2hU3yNkzARYFld");
- NSLog(@"EoFDRT7tiMcnJAasOzjBxmf");
- NSLog(@"vRetFjP5p3W");
- NSLog(@"3cyAzMKBZ0VuRFljC15NkHU");
- NSLog(@"t1NRCB78FPa");
- NSLog(@"DFlYJUcjP910qH");
- NSLog(@"Vs5KxiHMFhLzdnBal9tIguUAwfoGQD7y0c4");
- NSLog(@"5Uq8RFMYlaCOGJ3WKskeIcoA0BvmrdfDbtpy1P7H");
- NSLog(@"s19E4bqFQ5BH0X6lTIxLGCecKDidg");
- NSLog(@"7Qqzd0kNDKCoGSXcjV5hBb3xvYyAw86J");
- NSLog(@"wYp6RqkjvcDToQZ3StV");
- NSLog(@"Jk1aS4jcbryzERAY93v6uoUOTZw");
- NSLog(@"ZP2dX57kReFWKc39x6OSnVU");
- NSLog(@"jF8yd1aS5DpC0Ax29X");
- }
- -(void)arh48:(UIButton*) arh48 acX2nfQN:(UIDocument*) acX2nfQN avZoGHKLNq:(UIInputView*) avZoGHKLNq aArDRSx94h:(UIDocument*) aArDRSx94h aqEHaQ2xNBu:(UIMenuItem*) aqEHaQ2xNBu acaf7m14:(UIFont*) acaf7m14 a6V1QtIPbM:(UISearchBar*) a6V1QtIPbM a71xzDioT0:(UIBarButtonItem*) a71xzDioT0 aYT6Kp3:(UIMenuItem*) aYT6Kp3 a5Tb349LaZ:(UIRegion*) a5Tb349LaZ aC6kr7Kev:(UIScreen*) aC6kr7Kev {
- NSLog(@"MdByHbwplU6r");
- NSLog(@"sg37QcSN0a4JlVX5AWIjUemt");
- NSLog(@"ldOIa8ANCizMh0k7p6sjK2c5HBGUJtymX");
- NSLog(@"lFTVpiBPRXtvwAIu");
- NSLog(@"VtA2WoqHDSlk4GgyI0Qx9v");
- NSLog(@"JS8MKne2zuQklirOFj6CxqBcyNwPZbaoV");
- NSLog(@"mJjsC5uySNdiLkH");
- NSLog(@"duzl94kcvMqF");
- NSLog(@"0MIrgxn2wK5yWOTCD");
- NSLog(@"yrVL4aB9YIXeKjw03AxES6kvqUPgZ5t2D");
- NSLog(@"nTFw89H6f4qio");
- NSLog(@"2boINAr9M0nzVHPC");
- NSLog(@"wDLglNbZVeo7dW0H6ArOIaMxvk5Gp8");
- }
- @end
|