GitHub PullRequestReviewCommentEvent at 2014-06-03 21:49:07
Repository: bluekai-ios-sdk
Actor: shunchu
Payload: {"comment":{"url":"https://api.github.com/repos/BlueKai/bluekai-ios-sdk/pulls/comments/13361249","id":13361249,"diff_hunk":"@@ -0,0 +1,917 @@\n+#include <QuartzCore/QuartzCore.h>\n+#import \"BlueKai.h\"\n+#import \"BlueKai_Protected.h\"\n+#import \"BlueKai_Reachability.h\"\n+#import \"BlueKai_SBJSON.h\"\n+\n+@implementation BlueKai {\n+    BOOL _alertShowBool,\n+         _webLoaded;\n+\n+    int _urlLength,\n+        _numberOfRunningRequests;\n+\n+    UIButton  *_cancelButton;\n+    UISwitch  *_optInSwitch;\n+    UIWebView *_webView;\n+}\n+\n+\n+#pragma mark - Public Methods\n+\n+- (id)init {\n+    if (self = [super init]) {\n+        _appVersion = nil;\n+        _viewController = nil;\n+        _siteId = nil;\n+        _idfa = nil;\n+        _useHttps = NO;\n+        _devMode = NO;\n+        _optInPreference = YES;\n+        _userDefaults = [NSUserDefaults standardUserDefaults];\n+    }\n+\n+    return self;\n+}\n+\n+- (id)initWithSiteId:(NSString *)siteID withAppVersion:(NSString *)version withIdfa:(NSString *)idfa withView:(UIViewController *)view withDevMode:(BOOL)value {\n+    [self blueKaiLogger:_devMode withString:@\"init siteId \" withObject:siteID];\n+    [self blueKaiLogger:_devMode withString:@\"init appVersion \" withObject:version];\n+    [self blueKaiLogger:_devMode withString:@\"init view \" withObject:view];\n+    [self blueKaiLogger:_devMode withString:@\"init DevMode \" withObject:(value ? @\"YES\" : @\"NO\")];\n+\n+    if (self = [super init]) {\n+        _appVersion = version;\n+        _idfa = idfa;\n+        _devMode = value;\n+        _siteId = siteID;\n+        _viewController = view;\n+        _userDefaults = [NSUserDefaults standardUserDefaults];\n+        _optInPreference = [_userDefaults objectForKey:@\"userIsOptIn\"] == NULL ? YES : [[_userDefaults valueForKey:@\"userIsOptIn\"] boolValue];\n+        _cancelButton = nil;\n+        _webUrl = [[NSMutableString alloc] init];\n+        _nonLoadkeyValDict = [[NSMutableDictionary alloc] init];\n+        _remainkeyValDict = [[NSMutableDictionary alloc] init];\n+        _webLoaded = NO;\n+        _webView = [[UIWebView alloc] init];\n+        _webView.delegate = self;\n+        _webView.layer.cornerRadius = 5.0f;\n+        _webView.layer.borderColor = [[UIColor grayColor] CGColor];\n+        _webView.layer.borderWidth = 4.0f;\n+        [_viewController.view addSubview:_webView];\n+\n+        if (_devMode) {\n+            [self drawWebFrame:_webView];\n+        } else {\n+            _webView.frame = CGRectMake(10, 10, 1, 1);\n+        }\n+\n+        if (![_userDefaults objectForKey:@\"settings\"]) {\n+            [_userDefaults setObject:@\"NO\" forKey:@\"settings\"];\n+        }\n+\n+        if (![_userDefaults objectForKey:@\"userIsOptIn\"]) {\n+            [_userDefaults setObject:(_optInPreference ? @\"YES\" : @\"NO\") forKey:@\"userIsOptIn\"];\n+        }\n+\n+        [self saveSettings:nil];\n+\n+        _webView.hidden = YES;\n+\n+        // check the dictionary for previous values\n+        NSString *filePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];\n+        NSString *fileName = @\"user_data.bk\";\n+        NSString *fileAtPath = [filePath stringByAppendingPathComponent:fileName];\n+\n+        if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {\n+            [[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];\n+        }\n+\n+        NSString *atmt_filePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];\n+        NSString *atmt_fileName = @\"attempts.bk\";\n+        NSString *atmt_fileAtPath = [atmt_filePath stringByAppendingPathComponent:atmt_fileName];\n+\n+        if (![[NSFileManager defaultManager] fileExistsAtPath:atmt_fileAtPath]) {\n+            [[NSFileManager defaultManager] createFileAtPath:atmt_fileAtPath contents:nil attributes:nil];\n+        }\n+\n+        _keyValDict = [[NSMutableDictionary alloc] initWithDictionary:[self getKeyValueDictionary:[self readStringFromKeyValueFile]]];\n+\n+        if ([[_keyValDict allKeys] count] > 1) {\n+            _numberOfRunningRequests = -1;\n+//            [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;\n+            BlueKai_Reachability *networkReachability = [BlueKai_Reachability reachabilityForInternetConnection];\n+            NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];\n+\n+            if (networkStatus != NotReachable) {\n+                _webLoaded = YES;\n+                _webView.tag = 1;\n+                [self startDataUpload];\n+            } else {\n+                _alertShowBool = YES;\n+                [self webView:nil didFailLoadWithError:nil];\n+            }\n+        }\n+    }\n+\n+    return self;\n+}\n+\n+- (id)initWithSiteId:(NSString *)siteID withAppVersion:(NSString *)version withView:(UIViewController *)view withDevMode:(BOOL)devMode {\n+    return [self initWithSiteId:siteID withAppVersion:version withIdfa:nil withView:view withDevMode:devMode];\n+}\n+\n+- (void)setViewController:(UIViewController *)view {\n+    [self blueKaiLogger:_devMode withString:@\"setViewController\" withObject:view];\n+\n+    _viewController = view;\n+\n+    if (_siteId) {\n+        _webView = nil;\n+        _cancelButton = nil;\n+\n+        if (_webUrl) {\n+            [_webUrl replaceCharactersInRange:NSMakeRange(0, [_webUrl length]) withString:@\"\"];\n+        } else {\n+            _webUrl = [[NSMutableString alloc] init];\n+        }\n+\n+        _webView = [[UIWebView alloc] init];\n+        _webView.delegate = self;\n+        _webView.layer.cornerRadius = 5.0f;\n+        _webView.layer.borderColor = [[UIColor grayColor] CGColor];\n+        _webView.layer.borderWidth = 4.0f;\n+        [_viewController.view addSubview:_webView];\n+\n+        if(_devMode) {\n+            [self drawWebFrame:_webView];\n+        } else {\n+            _webView.frame = CGRectMake(1, 1, 1, 1);\n+        }\n+\n+        _webView.hidden = YES;\n+        [self resume];\n+    }\n+}\n+\n+- (void)resume {\n+    if (_webUrl) {\n+        [_webUrl replaceCharactersInRange:NSMakeRange(0, [_webUrl length]) withString:@\"\"];\n+    } else {\n+        _webUrl = [[NSMutableString alloc] init];\n+    }\n+\n+    _keyValDict = [[NSMutableDictionary alloc] initWithDictionary:[self getKeyValueDictionary:[self readStringFromKeyValueFile]]];\n+\n+    if ([[_keyValDict allKeys] count] > 0) {\n+        _numberOfRunningRequests = -1;\n+        BlueKai_Reachability *networkReachability = [BlueKai_Reachability reachabilityForInternetConnection];\n+        NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];\n+\n+        if (networkStatus != NotReachable) {\n+            _webView.tag = 1;\n+            [self startDataUpload];\n+        } else {\n+            [self webView:nil didFailLoadWithError:nil];\n+        }\n+    }\n+}\n+\n+- (void)updateWithKey:(NSString *)key andValue:(NSString *)value {\n+    [self blueKaiLogger:_devMode withString:@\"updateWithKeyValue:key\" withObject:key];\n+    [self blueKaiLogger:_devMode withString:@\"updateWithKeyValue:value\" withObject:value];\n+\n+    if (_webLoaded) {\n+        [_nonLoadkeyValDict setValue:value forKey:key];\n+    } else {\n+        if (_webUrl) {\n+            [_webUrl replaceCharactersInRange:NSMakeRange(0, [_webUrl length]) withString:@\"\"];\n+        } else {\n+            _webUrl = [[NSMutableString alloc] init];\n+        }\n+\n+        if (_keyValDict) {\n+            [_keyValDict removeAllObjects];\n+        } else {\n+            _keyValDict = [[NSMutableDictionary alloc] init];\n+        }\n+\n+        [_keyValDict setValue:[value copy] forKey:[key copy]];\n+    }\n+\n+    [self uploadIfNetworkIsAvailable];\n+}\n+\n+- (void)updateWithDictionary:(NSDictionary *)dictionary {\n+    [self blueKaiLogger:_devMode withString:@\"updateWithDictionary\" withObject:dictionary];\n+\n+    if (_webUrl) {\n+        [_webUrl replaceCharactersInRange:NSMakeRange(0, [_webUrl length]) withString:@\"\"];\n+    } else {\n+        _webUrl = [[NSMutableString alloc] init];\n+    }\n+\n+    if (_keyValDict) {\n+        [_keyValDict removeAllObjects];\n+    } else {\n+        _keyValDict = [[NSMutableDictionary alloc] init];\n+    }\n+\n+    [_keyValDict setValuesForKeysWithDictionary:dictionary];\n+\n+    [self uploadIfNetworkIsAvailable];\n+}\n+\n+- (void)setOptInPreference:(BOOL)optIn {\n+    _optInPreference = optIn;\n+\n+    [self blueKaiLogger:_devMode withString:@\"setOptInPreference:OptIn\" withObject:(_optInPreference ? @\"YES\" : @\"NO\")];\n+\n+    [_userDefaults setObject:(_optInPreference ? @\"YES\" : @\"NO\") forKey:@\"userIsOptIn\"];\n+\n+    [self saveSettings:nil];\n+    // TODO: Turn this back on when we can universally opt-out of BKSID\n+    //[self saveOptInPrefsOnServer];\n+}\n+\n+- (void)showSettingsScreen {\n+    [self showSettingsScreenWithBackgroundColor:nil];\n+}\n+\n+- (void)showSettingsScreenWithBackgroundColor:(UIColor *)backgroundColor {\n+    UIColor *bgColor = backgroundColor ? backgroundColor : [UIColor whiteColor];\n+\n+    _viewController.view.hidden = NO;\n+    _viewController.view.backgroundColor = bgColor;\n+\n+    _optInSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(238, 58, 0, 0)];\n+    [_optInSwitch setBackgroundColor:[UIColor whiteColor]];\n+    [_optInSwitch.layer setCornerRadius:16];\n+    [_optInSwitch setOn:_optInPreference];\n+    [_optInSwitch addTarget:self action:@selector(optInPreferenceChanged:) forControlEvents:UIControlEventValueChanged];\n+    [_viewController.view addSubview:_optInSwitch];\n+\n+    UILabel *usrData_lbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 48, 240, 50)];\n+    usrData_lbl.textColor = [UIColor blackColor];\n+    usrData_lbl.backgroundColor = [UIColor clearColor];\n+    usrData_lbl.textAlignment = NSTextAlignmentLeft;\n+    usrData_lbl.numberOfLines = 0;\n+    usrData_lbl.lineBreakMode = NSLineBreakByWordWrapping;\n+    usrData_lbl.font = [UIFont systemFontOfSize:14];\n+    usrData_lbl.text = @\"Allow Bluekai to receive my data\";\n+    [_viewController.view addSubview:usrData_lbl];\n+\n+    UILabel *tclbl = [[UILabel alloc] initWithFrame:CGRectMake(18, 234, 280, 50)];\n+    tclbl.textColor = [UIColor blackColor];\n+    tclbl.backgroundColor = [UIColor clearColor];\n+    tclbl.textAlignment = NSTextAlignmentLeft;\n+    tclbl.numberOfLines = 3;\n+    tclbl.lineBreakMode = NSLineBreakByWordWrapping;\n+    tclbl.font = [UIFont systemFontOfSize:14];\n+    tclbl.text = @\"The BlueKai privacy policy is available\";\n+    [_viewController.view addSubview:tclbl];\n+\n+    UIButton *Here = [UIButton buttonWithType:UIButtonTypeCustom];\n+    Here.frame = CGRectMake(256, 253, 50, 14);\n+    [Here setTitle:@\"here\" forState:UIControlStateNormal];\n+    Here.titleLabel.font = [UIFont systemFontOfSize:14];\n+    [Here addTarget:self action:@selector(termsConditions:) forControlEvents:UIControlEventTouchUpInside];\n+    [Here setTitleColor:[UIColor redColor] forState:UIControlStateNormal];\n+    [_viewController.view addSubview:Here];\n+\n+    UIButton *savebtn = [UIButton buttonWithType:UIButtonTypeCustom];\n+    savebtn.frame = CGRectMake(75, 290, 80, 35);\n+    [savebtn setTitle:@\"Save\" forState:UIControlStateNormal];\n+    [savebtn.layer setBorderWidth:2.0f];\n+    [savebtn.layer setBorderColor:[[UIColor grayColor] CGColor]];\n+    [savebtn.layer setCornerRadius:5.0f];\n+    [savebtn setBackgroundColor:[UIColor whiteColor]];\n+    [savebtn addTarget:self action:@selector(saveSettings:) forControlEvents:UIControlEventTouchUpInside];\n+    [savebtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];\n+    [_viewController.view addSubview:savebtn];\n+\n+    UIButton *cancelbtn = [UIButton buttonWithType:UIButtonTypeCustom];\n+    cancelbtn.frame = CGRectMake(175, 290, 80, 35);\n+    [cancelbtn setTitle:@\"Cancel\" forState:UIControlStateNormal];\n+    [cancelbtn.layer setBorderWidth:2.0f];\n+    [cancelbtn.layer setBorderColor:[[UIColor grayColor] CGColor]];\n+    [cancelbtn.layer setCornerRadius:5.0f];\n+    [cancelbtn setBackgroundColor:[UIColor whiteColor]];\n+    [cancelbtn addTarget:self action:@selector(Cancelbtn:) forControlEvents:UIControlEventTouchUpInside];\n+    [cancelbtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];\n+    [_viewController.view addSubview:cancelbtn];\n+    [_viewController.view addSubview:_webView];\n+    [_viewController.view addSubview:_cancelButton];\n+}\n+\n+\n+#pragma mark - Deprecated Methods\n+\n+- (id)initWithArgs:(BOOL)value withSiteId:(NSString *)siteID withAppVersion:(NSString *)version withView:(UIViewController *)view {\n+    [self blueKaiLogger:_devMode withString:@\"WARNING: [DEPRECATED] Please use the \\\"- (void) InitWithSiteId:withAppVersion:withView:withDevMode\\\" method instead\" withObject:nil];\n+    return [self initWithSiteId:siteID withAppVersion:version withView:view withDevMode:value];\n+}\n+\n+- (void)setPreference:(BOOL)optIn {\n+    [self blueKaiLogger:_devMode withString:@\"WARNING: [DEPRECATED] Please use the \\\"- (void) setOptInPreference\\\" method instead\" withObject:nil];\n+    [self setOptInPreference:optIn];\n+}\n+\n+- (void)put:(NSString *)key withValue:(NSString *)value {\n+    [self blueKaiLogger:_devMode withString:@\"WARNING: [DEPRECATED] Please use the \\\"- (void) updateWithKey:andValue\\\" method instead\" withObject:nil];\n+    [self updateWithKey:key andValue:value];\n+}\n+\n+- (void)put:(NSDictionary *)dictionary {\n+    [self blueKaiLogger:_devMode withString:@\"WARNING: [DEPRECATED] Please use the \\\"- (void) updateWithDictionary\\\" method instead\" withObject:nil];\n+    [self updateWithDictionary:dictionary];\n+}\n+\n+\n+#pragma mark - Objective-C Method overrides\n+\n+- (NSString *)description {\n+    return [NSString stringWithFormat:@\"<%@: %p, %@>\",\n+                                      [self class],\n+                                      self,\n+                                      @{\n+                                          @\"appVersion\": _appVersion,\n+                                          @\"devMode\": _devMode ? @\"YES\" : @\"NO\",\n+                                          @\"idfa\": _idfa,\n+                                          @\"optInPreference\": _optInPreference ? @\"YES\" : @\"NO\",\n+                                          @\"siteID\": _siteId,\n+                                          @\"useHTTPS\": _useHttps ? @\"YES\" : @\"NO\",\n+                                          @\"view\": _viewController\n+                                      }];\n+}\n+\n+- (NSString *)debugDescription {\n+    return [self description];\n+}\n+\n+\n+#pragma mark - IBActions\n+\n+- (IBAction)termsConditions:(id)sender {\n+    NSString *shareUrlString = [NSString stringWithFormat:@\"http://www.bluekai.com/consumers_privacyguidelines.php\"];\n+\n+    NSURL *HereUrl = [[NSURL alloc] initWithString:shareUrlString];\n+    //Create the URL object\n+\n+    [[UIApplication sharedApplication] openURL:HereUrl];\n+    //Launch Safari with the URL you created\n+}\n+\n+- (IBAction)Cancelbtn:(id)sender {\n+    [self blueKaiLogger:_devMode withString:@\"cancel opt-in view\" withObject:nil];\n+    _viewController.view.hidden = YES;\n+}\n+\n+- (IBAction)Cancel:(id)sender {\n+    _webView.hidden = YES;\n+    _cancelButton.hidden = YES;\n+}\n+\n+- (IBAction)saveSettings:(id)sender {\n+//    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;\n+    NSString *userDataValue = [_userDefaults objectForKey:@\"userIsOptIn\"];\n+    [_userDefaults setObject:userDataValue forKey:@\"settings\"];\n+\n+    // TODO: Turn this back on when we can universally opt-out of BKSID\n+    // [self saveOptInPrefsOnServer];\n+\n+    // TODO: Remove when BKSID opt-out is implemented; may need to be deprecated\n+    id <BlueKaiOnDataPostedListener> localDelegate = _delegate;\n+\n+    if ([localDelegate respondsToSelector:@selector(onDataPosted:)]) {\n+        [localDelegate onDataPosted:FALSE];\n+    }\n+    // end TODO\n+}\n+\n+\n+#pragma mark - Private Methods\n+\n+- (void)writeStringToKeyValueFile:(NSString *)aString {\n+    // Build the path, and create if needed.\n+    NSString *filePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];\n+    NSString *fileName = @\"user_data.bk\";\n+    NSString *fileAtPath = [filePath stringByAppendingPathComponent:fileName];\n+\n+    if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {\n+        [[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];\n+    } else {\n+        [[NSFileManager defaultManager] removeItemAtPath:fileAtPath error:nil];\n+    }\n+    // The main act...\n+    [[aString dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];\n+}\n+\n+- (NSString *)readStringFromKeyValueFile {\n+    // Build the path...\n+    NSString *filePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];\n+    NSString *fileName = @\"user_data.bk\";\n+    NSString *fileAtPath = [filePath stringByAppendingPathComponent:fileName];\n+    if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {\n+        [[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];\n+        return [NSString string];\n+    } else {\n+        return [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding];\n+    }\n+    // The main act...\n+}\n+\n+- (NSString *)getKeyValueJSON:(NSMutableDictionary *)keyValues {\n+    @try {\n+        NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithDictionary:keyValues];\n+        BlueKai_SBJsonWriter *sb = [[BlueKai_SBJsonWriter alloc] init];\n+        NSString *jsonString = [sb stringWithObject:dictionary];\n+\n+        return jsonString;\n+    }\n+    @catch (NSException *ex) {\n+        [self blueKaiLogger:_devMode withString:@\"Exception is \" withObject:ex];\n+\n+        return nil;\n+    }\n+}\n+\n+- (NSDictionary *)getKeyValueDictionary:(NSString *)jsonString {\n+    BlueKai_SBJSON *sparser = [[BlueKai_SBJSON alloc] init];\n+    NSDictionary *realdata = (NSDictionary *) [sparser objectWithString:jsonString error:nil];\n+    return realdata;\n+}\n+\n+- (void)writeStringToAttemptsFile:(NSString *)aString {\n+    // Build the path, and create if needed.\n+    NSString *filePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];\n+    NSString *fileName = @\"attempts.bk\";\n+    NSString *fileAtPath = [filePath stringByAppendingPathComponent:fileName];\n+\n+    if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {\n+        [[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];\n+    } else {\n+        [[NSFileManager defaultManager] removeItemAtPath:fileAtPath error:nil];\n+    }\n+\n+    // The main act...\n+    [[aString dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];\n+}\n+\n+- (NSString *)readStringFromAttemptsFile {\n+    // Build the path...\n+    NSString *filePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];\n+    NSString *fileName = @\"attempts.bk\";\n+    NSString *fileAtPath = [filePath stringByAppendingPathComponent:fileName];\n+\n+    // The main act...\n+    return [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding];\n+}\n+\n+- (NSString *)getAttemptsJSON:(NSMutableDictionary *)keyValues {\n+    [self blueKaiLogger:_devMode withString:@\"getAttemptsJSON: \" withObject:keyValues];\n+\n+    @try {\n+        NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:keyValues];\n+        BlueKai_SBJsonWriter *sb = [[BlueKai_SBJsonWriter alloc] init];\n+        NSString *jsonString = [sb stringWithObject:dict];\n+        return jsonString;\n+    }\n+\n+    @catch (NSException *ex) {\n+        [self blueKaiLogger:_devMode withString:@\"Exception is \" withObject:ex];\n+        return nil;\n+    }\n+}\n+\n+- (NSDictionary *)getAttemptsDictionary:(NSString *)jsonString {\n+    [self blueKaiLogger:_devMode withString:@\"getAttemptsDictionary\" withObject:jsonString];\n+    BlueKai_SBJSON *sparser = [[BlueKai_SBJSON alloc] init];\n+    NSDictionary *realData = (NSDictionary *) [sparser objectWithString:jsonString error:nil];\n+    return realData;\n+}\n+\n+- (void)saveOptInPrefsOnServer {\n+    _numberOfRunningRequests = -1;\n+    BlueKai_Reachability *networkReachability = [BlueKai_Reachability reachabilityForInternetConnection];\n+    NetworkStatus networkStatus = [networkReachability currentReachabilityStatus];\n+\n+    if (networkStatus != NotReachable) {\n+        UIWebView *optInWebView = [[UIWebView alloc] init];\n+        // use mobileproxy for development\n+        NSString *server = _devMode ? @\"http://mobileproxy.bluekai.com/\" : @\"http://tags.bluekai.com/\";\n+        NSString *urlPath = [[_userDefaults objectForKey:@\"userIsOptIn\"] isEqualToString:@\"YES\"] ? @\"clear_ignore\" : @\"set_ignore\";\n+        NSMutableString *url = [[NSMutableString alloc] initWithString:[NSString stringWithFormat:@\"%@%@\", server, urlPath]];\n+\n+        [self blueKaiLogger:_devMode withString:@\"opt-in preference is set to\" withObject:[_userDefaults objectForKey:@\"userIsOptIn\"]];\n+//        [self blueKaiLogger:_devMode withString:@\"opt-in URL\" withObject:url];\n+\n+        [_viewController.view addSubview:optInWebView];\n+        [optInWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];\n+    } else {\n+        [self webView:nil didFailLoadWithError:nil];\n+    }\n+}\n+\n+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {\n+    [self blueKaiLogger:_devMode withString:@\"Web View Error\" withObject:error];\n+\n+    // to avoid the \"Weak receiver may be unpredictably null in ARC mode\" warning\n+    id <BlueKaiOnDataPostedListener> localDelegate = _delegate;\n+\n+    if ([localDelegate respondsToSelector:@selector(onDataPosted:)]) {\n+        [localDelegate onDataPosted:FALSE];\n+    }\n+\n+    if (_numberOfRunningRequests != 0) {\n+        _numberOfRunningRequests = 0;\n+\n+//        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;\n+\n+        for (int i = 0; i < [[_keyValDict allKeys] count]; i++) {\n+            if (![_remainkeyValDict valueForKey:[_keyValDict allKeys][i]]) {\n+                NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithDictionary:[self getKeyValueDictionary:[self readStringFromKeyValueFile]]];\n+                NSMutableDictionary *atmt_dictionary = [[NSMutableDictionary alloc] initWithDictionary:[self getAttemptsDictionary:[self readStringFromAttemptsFile]]];\n+                int attempts = [atmt_dictionary[[_keyValDict allKeys][i]] intValue];\n+\n+                if (attempts == 0) {\n+                    dictionary[[_keyValDict allKeys][i]] = [_keyValDict valueForKey:[_keyValDict allKeys][i]];\n+                    atmt_dictionary[[_keyValDict allKeys][i]] = @\"1\";\n+                } else {\n+                    if (attempts < 5) {\n+                        [atmt_dictionary removeObjectForKey:[_keyValDict allKeys][i]];\n+                        atmt_dictionary[[_keyValDict allKeys][i]] = [NSString stringWithFormat:@\"%d\", attempts + 1];\n+                    } else {\n+                        [dictionary removeObjectForKey:[_keyValDict allKeys][i]];\n+                        [atmt_dictionary removeObjectForKey:[_keyValDict allKeys][i]];\n+                    }\n+                }\n+\n+                [self writeStringToKeyValueFile:[self getKeyValueJSON:dictionary]];\n+                [self writeStringToAttemptsFile:[self getAttemptsJSON:atmt_dictionary]];\n+            }\n+        }\n+\n+        _webLoaded = NO;\n+\n+        if (_remainkeyValDict || _nonLoadkeyValDict) {\n+            if ([_remainkeyValDict count] != 0 || [_nonLoadkeyValDict count] != 0) {\n+                [self loadAnotherRequest];\n+            }\n+        }\n+    }\n+}\n+\n+- (void)updateWebview:(NSString *)url {\n+    [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];\n+}\n+\n+- (void)webViewDidStartLoad:(UIWebView *)webView {\n+    // if \"_numberOfRunningRequests\" is not -1, increment by 1; otherwise (0 or -1) set it back to 1\n+    _numberOfRunningRequests = _numberOfRunningRequests != -1 ? _numberOfRunningRequests + 1 : 1;\n+}\n+\n+- (void)webViewDidFinishLoad:(UIWebView *)webView {\n+    _numberOfRunningRequests = _numberOfRunningRequests - 1;\n+    // to avoid the \"Weak receiver may be unpredictably null in ARC mode\" warning\n+    id <BlueKaiOnDataPostedListener> localDelegate = _delegate;\n+\n+\n+    if (_numberOfRunningRequests == 0) {\n+        if (!_alertShowBool) {\n+            if (_webView.tag == 1) {\n+                //Delete the key and value pairs from database after sent to server.\n+                for (int k = 0; k < [_keyValDict count]; k++) {\n+//                    if (![_remainkeyValDict valueForKey:[_keyValDict allKeys][k]]) {\n+                    if ([_remainkeyValDict valueForKey:[_keyValDict allKeys][k]] != NULL) {\n+                        NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithDictionary:[self getKeyValueDictionary:[self readStringFromKeyValueFile]]];\n+                        NSMutableDictionary *atmt_dictionary = [[NSMutableDictionary alloc] initWithDictionary:[self getAttemptsDictionary:[self readStringFromAttemptsFile]]];\n+                        int attempts = [atmt_dictionary[[_keyValDict allKeys][k]] intValue];\n+\n+                        if (attempts != 0) {\n+                            [dictionary removeObjectForKey:[_keyValDict allKeys][k]];\n+                            [atmt_dictionary removeObjectForKey:[_keyValDict allKeys][k]];\n+                            [self writeStringToKeyValueFile:[self getKeyValueJSON:dictionary]];\n+                            [self writeStringToAttemptsFile:[self getAttemptsJSON:atmt_dictionary]];\n+                        }\n+                    }\n+                }\n+            }\n+\n+            if (_devMode) {\n+                _webView.hidden = NO;\n+                _cancelButton.hidden = NO;\n+            }\n+\n+            _webLoaded = NO;\n+//            [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;\n+\n+            if ([localDelegate respondsToSelector:@selector(onDataPosted:)]) {\n+                [localDelegate onDataPosted:TRUE];\n+            }\n+\n+            [self blueKaiLogger:_devMode withString:@\"URL loaded\" withObject:webView.request.URL];\n+            _alertShowBool = YES;\n+\n+            if (_remainkeyValDict || _nonLoadkeyValDict) {\n+                if ([_remainkeyValDict count] != 0 || [_nonLoadkeyValDict count] != 0) {\n+                    [self loadAnotherRequest];\n+                }\n+            }\n+\n+            NSArray *webViews = [_viewController.view subviews];\n+            int web_count = 0;\n+            int btn_count = 0;\n+\n+            for (UIView *view in webViews) {\n+                if ([view isKindOfClass:[UIWebView class]]) {\n+                    web_count++;\n+                } else {\n+                    if ([view isKindOfClass:[UIButton class]]) {\n+                        if (view.tag == 10) {\n+                            btn_count++;\n+                        }\n+                    }\n+                }\n+            }\n+\n+            if (web_count > 1) {\n+                for (UIView *view in webViews) {\n+                    if ([view isKindOfClass:[UIWebView class]]) {\n+                        if (web_count >= 2) {\n+                            [view removeFromSuperview];\n+                            web_count--;\n+                        } else {\n+                            view.hidden = YES;\n+                        }\n+                    } else {\n+                        if ([view isKindOfClass:[UIButton class]]) {\n+                            if (view.tag == 10) {\n+                                if (btn_count >= 2) {\n+                                    [view removeFromSuperview];\n+                                    btn_count--;\n+                                } else {\n+                                    view.hidden = YES;\n+                                }\n+                            }\n+                        }\n+                    }\n+                }\n+            }\n+        }\n+    }\n+}\n+\n+- (void)loadAnotherRequest {\n+    [self blueKaiLogger:_devMode withString:@\"loadAnotherRequest\" withObject:nil];\n+\n+    if ([_remainkeyValDict count] == 0) {\n+        if ([_nonLoadkeyValDict count] != 0) {\n+            _webView = [[UIWebView alloc] init];\n+            _webView.delegate = self;\n+            _webView.layer.cornerRadius = 5.0f;\n+            _webView.layer.borderColor = [[UIColor grayColor] CGColor];\n+            _webView.layer.borderWidth = 4.0f;\n+            _webView.hidden = YES;\n+            [_viewController.view addSubview:_webView];\n+\n+            if (_devMode) {\n+                [self drawWebFrame:_webView];\n+            } else {\n+                _webView.frame = CGRectMake(10, 10, 1, 1);\n+            }\n+\n+            _webLoaded = NO;\n+\n+            if (_keyValDict) {\n+                [_keyValDict removeAllObjects];\n+            } else {\n+                _keyValDict = [[NSMutableDictionary alloc] init];\n+            }\n+\n+            _numberOfRunningRequests = -1;\n+\n+            if (_webUrl) {\n+                [_webUrl replaceCharactersInRange:NSMakeRange(0, [_webUrl length]) withString:@\"\"];\n+            } else {\n+                _webUrl = [[NSMutableString alloc] init];\n+            }\n+\n+            //Code to send the multiple values for every request.\n+\n+            for (int i = 0; i < [[_nonLoadkeyValDict allKeys] count]; i++) {\n+                NSString *key = [NSString stringWithFormat:@\"%@\", [_nonLoadkeyValDict allKeys][i]];\n+                NSString *value = [NSString stringWithFormat:@\"%@\", _nonLoadkeyValDict[[_nonLoadkeyValDict allKeys][i]]];\n+\n+                if ((_urlLength + key.length + value.length + 2) <= 255) {\n+                    [_keyValDict setValue:[_nonLoadkeyValDict valueForKey:[_nonLoadkeyValDict allKeys][i]] forKey:[_nonLoadkeyValDict allKeys][i]];\n+                    _urlLength = _urlLength + key.length + value.length + 2;\n+                }\n+            }\n+\n+            for (int j = 0; j < [[_keyValDict allKeys] count]; j++) {\n+                [_nonLoadkeyValDict removeObjectForKey:[_keyValDict allKeys][j]];\n+            }\n+\n+//            [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;\n+            [self startDataUpload];\n+        } else {\n+            _nonLoadkeyValDict = nil;\n+            _remainkeyValDict = nil;\n+            _keyValDict = nil;\n+            _webUrl = nil;\n+        }\n+    } else {\n+        _webView = [[UIWebView alloc] init];\n+        _webView.delegate = self;\n+        _webView.layer.cornerRadius = 5.0f;\n+        _webView.layer.borderColor = [[UIColor grayColor] CGColor];\n+        _webView.layer.borderWidth = 4.0f;\n+        _webView.tag = 1;\n+        _webView.hidden = YES;\n+        [_viewController.view addSubview:_webView];\n+\n+        if (_devMode) {\n+            [self drawWebFrame:_webView];\n+        } else {\n+            _webView.frame = CGRectMake(10, 10, 1, 1);\n+        }\n+\n+        if (_keyValDict) {\n+            [_keyValDict removeAllObjects];\n+        } else {\n+            _keyValDict = [[NSMutableDictionary alloc] init];\n+        }\n+\n+        [_keyValDict setValuesForKeysWithDictionary:_remainkeyValDict];\n+\n+        if (_webUrl) {\n+            [_webUrl replaceCharactersInRange:NSMakeRange(0, [_webUrl length]) withString:@\"\"];\n+        } else {\n+            _webUrl = [[NSMutableString alloc] init];\n+        }\n+\n+        _numberOfRunningRequests = -1;\n+//        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;\n+        [self startDataUpload];\n+    }\n+}\n+\n+- (NSString *)urlEncode:(NSString *)string {\n+    NSMutableString *output = [NSMutableString string];\n+\n+    const unsigned char *source = (const unsigned char *) [string UTF8String];\n+    int sourceLen = strlen((const char *) source);\n+\n+    for (int i = 0; i < sourceLen; ++i) {\n+        const unsigned char thisChar = source[i];\n+\n+        // credit: http://stackoverflow.com/a/12927815/499700\n+        if (thisChar == ' ') {\n+            [output appendString:@\"+\"];\n+        } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' ||\n+                (thisChar >= 'a' && thisChar <= 'z') ||\n+                (thisChar >= 'A' && thisChar <= 'Z') ||\n+                (thisChar >= '0' && thisChar <= '9')) {\n+            [output appendFormat:@\"%c\", thisChar];\n+        } else {\n+            [output appendFormat:@\"%%%02X\", thisChar];\n+        }\n+    }\n+\n+    return output;\n+}\n+\n+- (void)optInPreferenceChanged:(id)sender {\n+    if ([sender isOn]) {\n+        [self setOptInPreference:YES];\n+        [_userDefaults setObject:@\"YES\" forKey:@\"userIsOptIn\"];\n+    } else {\n+        [self setOptInPreference:NO];\n+        [_userDefaults setObject:@\"NO\" forKey:@\"userIsOptIn\"];\n+    }\n+}\n+\n+- (void)startDataUpload {\n+    NSString *errorMessage;\n+    BOOL     hasError = NO;\n+\n+    if (!_viewController) {\n+        hasError = YES;\n+        errorMessage = @\"view parameter is nil\";\n+    }\n+\n+    if (!_siteId) {\n+        hasError = YES;\n+        errorMessage = @\"siteId parameter is nil\";\n+    }\n+\n+    if (!_appVersion) {\n+        hasError = YES;\n+        errorMessage = @\"appVersion parameter is nil\";","path":"sdk/Bluekai_SDK/BlueKai.m","position":811,"original_position":811,"commit_id":"fc3c6cd00901df49932b2d160a37bbccd3a8e9e6","original_commit_id":"fc3c6cd00901df49932b2d160a37bbccd3a8e9e6","user":{"login":"shunchu","id":651899,"avatar_url":"https://avatars.githubusercontent.com/u/651899?","gravatar_id":"56b4502c6e3b1ad69bf89e2144361d08","url":"https://api.github.com/users/shunchu","html_url":"https://github.com/shunchu","followers_url":"https://api.github.com/users/shunchu/followers","following_url":"https://api.github.com/users/shunchu/following{/other_user}","gists_url":"https://api.github.com/users/shunchu/gists{/gist_id}","starred_url":"https://api.github.com/users/shunchu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shunchu/subscriptions","organizations_url":"https://api.github.com/users/shunchu/orgs","repos_url":"https://api.github.com/users/shunchu/repos","events_url":"https://api.github.com/users/shunchu/events{/privacy}","received_events_url":"https://api.github.com/users/shunchu/received_events","type":"User","site_admin":false},"body":"`NSString`s are immutable. Only one error is possible at any given time in this block. So only one error will appear at any given time. Previous implementation had combination of errors but it was complicated, so I just distilled it down to this.","created_at":"2014-06-03T21:49:07Z","updated_at":"2014-06-03T21:49:07Z","html_url":"https://github.com/BlueKai/bluekai-ios-sdk/pull/6#discussion_r13361249","pull_request_url":"https://api.github.com/repos/BlueKai/bluekai-ios-sdk/pulls/6","_links":{"self":{"href":"https://api.github.com/repos/BlueKai/bluekai-ios-sdk/pulls/comments/13361249"},"html":{"href":"https://github.com/BlueKai/bluekai-ios-sdk/pull/6#discussion_r13361249"},"pull_request":{"href":"https://api.github.com/repos/BlueKai/bluekai-ios-sdk/pulls/6"}}}}