├── screens ├── demo.gif └── screen0.png ├── Example Project ├── ExampleProject │ ├── en.lproj │ │ ├── InfoPlist.strings │ │ ├── ViewController_iPad.xib │ │ └── ViewController_iPhone.xib │ ├── ModalViewController.h │ ├── ExampleProject-Prefix.pch │ ├── main.m │ ├── AppDelegate.h │ ├── ViewController.h │ ├── ModalViewController.m │ ├── ExampleProject-Info.plist │ ├── AppDelegate.m │ ├── ViewController.m │ ├── ModalViewController_iPhone.xib │ └── ModalViewController_iPad.xib ├── ShakingAlertViewKiwiTest │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── ShakingAlertViewKiwiTest-Prefix.pch │ ├── ShakingAlertViewKiwiTest-Info.plist │ └── ShakingAlertViewTests.m ├── Podfile ├── Default-568h@2x.png ├── Podfile.lock ├── ExampleProject.xcworkspace │ └── contents.xcworkspacedata └── ExampleProject.xcodeproj │ ├── project.xcworkspace │ └── contents.xcworkspacedata │ ├── xcuserdata │ └── luke.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist │ ├── xcshareddata │ └── xcschemes │ │ ├── ShakingAlertViewKiwiTest.xcscheme │ │ └── ShakingAlertView.xcscheme │ └── project.pbxproj ├── .gitignore ├── .travis.yml ├── src ├── b64.h ├── NSData+Base64.h ├── NSData+Base64.m ├── ShakingAlertView.h ├── b64.m └── ShakingAlertView.m ├── ShakingAlertView.podspec ├── License.txt └── README.md /screens/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukestringer90/ShakingAlertView/HEAD/screens/demo.gif -------------------------------------------------------------------------------- /screens/screen0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukestringer90/ShakingAlertView/HEAD/screens/screen0.png -------------------------------------------------------------------------------- /Example Project/ExampleProject/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example Project/ShakingAlertViewKiwiTest/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example Project/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios 2 | target :ShakingAlertViewKiwiTest, :exclusive => true do 3 | pod 'Kiwi' 4 | end -------------------------------------------------------------------------------- /Example Project/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukestringer90/ShakingAlertView/HEAD/Example Project/Default-568h@2x.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.xcodeproj/project.xcworkspace/* 3 | 4 | Example Project/Pods/* 5 | *.xcuserstate 6 | *.xcsettings 7 | *.xcbkptlist 8 | -------------------------------------------------------------------------------- /Example Project/Podfile.lock: -------------------------------------------------------------------------------- 1 | 2 | COCOAPODS: 0.16.1 3 | 4 | PODS: 5 | - Kiwi (2.0.4) 6 | 7 | DEPENDENCIES: 8 | - Kiwi 9 | 10 | SPEC CHECKSUMS: 11 | Kiwi: 44abe10fc11eb6a9e05d580211abd1f8fdb01260 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | before_install: 3 | - brew update 4 | - brew install xctool 5 | - cd Example\ Project 6 | - pod install 7 | script: xctool test -project ExampleProject.xcodeproj/ -scheme ShakingAlertView 8 | -------------------------------------------------------------------------------- /Example Project/ExampleProject.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example Project/ExampleProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example Project/ShakingAlertViewKiwiTest/ShakingAlertViewKiwiTest-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ShakingAlertViewKiwiTest' target in the 'ShakingAlertViewKiwiTest' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /src/b64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * b64.h 3 | * AQToolkit 4 | * 5 | * Created by Jim Dovey on 11-01-11. 6 | * Based on b64.c by Bob Trower 7 | * 8 | * 9 | */ 10 | 11 | #import 12 | 13 | NSData * b64_encode( NSData * data ); 14 | NSData * b64_decode( NSData * data ); 15 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/ModalViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModalViewController.h 3 | // ShakingAlertView 4 | // 5 | // Created by Luke on 21/09/2012. 6 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ModalViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/ExampleProject-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ShakingAlertView' target in the 'ShakingAlertView' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ShakingAlertView 4 | // 5 | // Created by Luke on 23/09/2012. 6 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ShakingAlertView 4 | // 5 | // Created by Luke on 23/09/2012. 6 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ViewController; 12 | 13 | @interface AppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @property (strong, nonatomic) ViewController *viewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ShakingAlertView 4 | // 5 | // Created by Luke on 21/09/2012. 6 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ShakingAlertView.h" 11 | 12 | 13 | @interface ViewController : UIViewController 14 | 15 | - (IBAction)plainTextLoginTapped:(id)sender; 16 | - (IBAction)sha1LoginTapped:(id)sender; 17 | - (IBAction)md5LoginTaped:(id)sender; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Example Project/ShakingAlertViewKiwiTest/ShakingAlertViewKiwiTest-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.lukestringer.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example Project/ExampleProject.xcodeproj/xcuserdata/luke.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ShakingAlertView.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | ShakingAlertViewKiwiTest.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | A33909CB160F17D80083C023 21 | 22 | primary 23 | 24 | 25 | A3F40CCD16D189F900E5FA63 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ShakingAlertView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ShakingAlertView" 3 | s.version = "1.0.0" 4 | s.summary = "UIAlertView subclass containing a password entry field and a 'shake' animation for incorrect password entry." 5 | s.description = "ShakingAlertView is a UIAlertView subclass with a password entry textfield. Incorrect password entry causes a 'shake' animation similar to the OS X account login screen." 6 | s.homepage = "https://github.com/stringer630/ShakingAlertView" 7 | s.screenshots = "https://raw.github.com/stringer630/ShakingAlertView/master/screens/screen0.png" 8 | s.license = { :type => 'MIT', :file => 'License.txt' } 9 | s.author = { "Luke Stringer" => "luke.stringer@me.com" } 10 | s.source = { :git => "https://github.com/stringer630/ShakingAlertView.git", :tag => "1.0.0" } 11 | s.ios.deployment_target = '5.0' 12 | s.source_files = 'src' 13 | s.requires_arc = true 14 | end 15 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | This code is distributed under the terms and conditions of the MIT license. 2 | 3 | Copyright (c) 2012 Luke Stringer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Example Project/ExampleProject/ModalViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModalViewController.m 3 | // ShakingAlertView 4 | // 5 | // Created by Luke on 21/09/2012. 6 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 7 | // 8 | 9 | #import "ModalViewController.h" 10 | 11 | 12 | 13 | @implementation ModalViewController 14 | 15 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 16 | { 17 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 18 | if (self) { 19 | // Custom initialization 20 | } 21 | return self; 22 | } 23 | 24 | - (void)viewDidLoad 25 | { 26 | [super viewDidLoad]; 27 | // Do any additional setup after loading the view from its nib. 28 | 29 | self.title = @"Password Protected"; 30 | 31 | UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(dismissModalViewControllerAnimated:)]; 32 | self.navigationItem.rightBarButtonItem = doneButton; 33 | } 34 | 35 | - (void)viewDidUnload 36 | { 37 | [super viewDidUnload]; 38 | // Release any retained subviews of the main view. 39 | // e.g. self.myOutlet = nil; 40 | } 41 | 42 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 43 | { 44 | return (interfaceOrientation == UIInterfaceOrientationPortrait); 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/ExampleProject-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.lukestringer.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/NSData+Base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NSData+Base64.h 3 | * AQToolkit 4 | * 5 | * Created by Jim Dovey on 31/8/2008. 6 | * 7 | * Copyright (c) 2008-2009, Jim Dovey 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * 17 | * Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 21 | * Neither the name of this project's author nor the names of its 22 | * contributors may be used to endorse or promote products derived from 23 | * this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | #import 40 | 41 | @class NSString; 42 | 43 | @interface NSData (Base64) 44 | 45 | + (NSData *) dataFromBase64String: (NSString *) base64String; 46 | - (id) initWithBase64String: (NSString *) base64String; 47 | - (NSString *) base64EncodedString; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Example Project/ExampleProject.xcodeproj/xcshareddata/xcschemes/ShakingAlertViewKiwiTest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 36 | 37 | 38 | 39 | 45 | 46 | 48 | 49 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/NSData+Base64.m: -------------------------------------------------------------------------------- 1 | /* 2 | * NSData+Base64.h 3 | * AQToolkit 4 | * 5 | * Created by Jim Dovey on 31/8/2008. 6 | * 7 | * Copyright (c) 2008-2009, Jim Dovey 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * 17 | * Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 21 | * Neither the name of this project's author nor the names of its 22 | * contributors may be used to endorse or promote products derived from 23 | * this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * 37 | */ 38 | 39 | #import 40 | #import "NSData+Base64.h" 41 | #import "b64.h" 42 | 43 | @implementation NSData (Base64) 44 | 45 | + (NSData *) dataFromBase64String: (NSString *) base64String 46 | { 47 | NSData * charData = [base64String dataUsingEncoding: NSUTF8StringEncoding]; 48 | return ( b64_decode(charData) ); 49 | } 50 | 51 | - (id) initWithBase64String: (NSString *) base64String 52 | { 53 | NSData * charData = [base64String dataUsingEncoding: NSUTF8StringEncoding]; 54 | NSData * result = b64_decode(charData); // we'll return this with 1 extant retain count 55 | return ( result ); 56 | } 57 | 58 | - (NSString *) base64EncodedString 59 | { 60 | NSData * charData = b64_encode( self ); 61 | return ( [[NSString alloc] initWithData: charData encoding: NSUTF8StringEncoding] ); 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ShakingAlertView 4 | // 5 | // Created by Luke on 23/09/2012. 6 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "ViewController.h" 12 | 13 | @implementation AppDelegate 14 | 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 19 | // Override point for customization after application launch. 20 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 21 | self.viewController = [[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil]; 22 | } else { 23 | self.viewController = [[ViewController alloc] initWithNibName:@"ViewController_iPad" bundle:nil]; 24 | } 25 | self.window.rootViewController = self.viewController; 26 | [self.window makeKeyAndVisible]; 27 | return YES; 28 | } 29 | 30 | - (void)applicationWillResignActive:(UIApplication *)application 31 | { 32 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 33 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 34 | } 35 | 36 | - (void)applicationDidEnterBackground:(UIApplication *)application 37 | { 38 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 40 | } 41 | 42 | - (void)applicationWillEnterForeground:(UIApplication *)application 43 | { 44 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 45 | } 46 | 47 | - (void)applicationDidBecomeActive:(UIApplication *)application 48 | { 49 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 50 | } 51 | 52 | - (void)applicationWillTerminate:(UIApplication *)application 53 | { 54 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /src/ShakingAlertView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ShakingAlertView.h 3 | // 4 | // Created by Luke on 21/09/2012. 5 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 6 | // 7 | // https://github.com/stringer630/ShakingAlertView 8 | // 9 | 10 | // This code is distributed under the terms and conditions of the MIT license. 11 | // 12 | // Copyright (c) 2012 Luke Stringer 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in 22 | // all copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | // THE SOFTWARE. 31 | 32 | #import 33 | 34 | typedef enum { 35 | HashTechniqueNone, 36 | HashTechniqueSHA1, 37 | HashTechniqueMD5 38 | } HashTechnique; 39 | 40 | 41 | @interface ShakingAlertView : UIAlertView 42 | 43 | @property (nonatomic, strong) NSString *password; 44 | 45 | @property (nonatomic, copy) void(^onCorrectPassword)(); 46 | @property (nonatomic, copy) void(^onDismissalWithoutPassword)(); 47 | 48 | @property (assign) HashTechnique hashTechnique; 49 | 50 | 51 | // Constructors for plaintext password 52 | - (id)initWithAlertTitle:(NSString *)title 53 | checkForPassword:(NSString *)password; 54 | 55 | - (id)initWithAlertTitle:(NSString *)title 56 | checkForPassword:(NSString *)password 57 | onCorrectPassword:(void(^)())correctPasswordBlock 58 | onDismissalWithoutPassword:(void(^)())dismissalWithoutPasswordBlock; 59 | 60 | 61 | // Constructors for hashed passwords 62 | - (id)initWithAlertTitle:(NSString *)title 63 | checkForPassword:(NSString *)password 64 | usingHashingTechnique:(HashTechnique)hashingTechnique; 65 | 66 | - (id)initWithAlertTitle:(NSString *)title 67 | checkForPassword:(NSString *)password 68 | usingHashingTechnique:(HashTechnique)hashingTechnique 69 | onCorrectPassword:(void(^)())correctPasswordBlock 70 | onDismissalWithoutPassword:(void(^)())dismissalWithoutPasswordBlock; 71 | 72 | @end 73 | 74 | -------------------------------------------------------------------------------- /Example Project/ExampleProject.xcodeproj/xcshareddata/xcschemes/ShakingAlertView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ShakingAlertView 4 | // 5 | // Created by Luke on 21/09/2012. 6 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 7 | // 8 | // 9 | // 10 | 11 | #import "ViewController.h" 12 | #import "ModalViewController.h" 13 | 14 | @implementation ViewController 15 | 16 | #pragma mark - IBActions 17 | - (IBAction)plainTextLoginTapped:(id)sender { 18 | 19 | // Make the alert 20 | // Here was are using a plantext password check 21 | ShakingAlertView *shakingAlert = [[ShakingAlertView alloc] initWithAlertTitle:@"Enter Password" 22 | checkForPassword:@"password"]; 23 | 24 | // Block to excute on success 25 | [shakingAlert setOnCorrectPassword:^{ 26 | // Show a modal view 27 | [self showModalView]; 28 | 29 | }]; 30 | 31 | // Block to execute on alert dismissal 32 | [shakingAlert setOnDismissalWithoutPassword:^{ 33 | // Show regular UIAlertView to give them another go 34 | [self showFailedPasswordAlert]; 35 | 36 | }]; 37 | 38 | // Show and release 39 | [shakingAlert show]; 40 | 41 | } 42 | 43 | - (IBAction)sha1LoginTapped:(id)sender { 44 | // Make the alert 45 | // Speficify we want to use SHA1 hashing 46 | ShakingAlertView *shakingAlert = [[ShakingAlertView alloc] 47 | initWithAlertTitle:@"Enter Password" 48 | checkForPassword:@"W6ph5Mm5Pz8GgiULbPgzG37mj9g=" //SHA1 hash of 'password' 49 | usingHashingTechnique:HashTechniqueSHA1]; 50 | 51 | // Block to excute on success 52 | [shakingAlert setOnCorrectPassword:^{ 53 | // Show a modal view 54 | [self showModalView]; 55 | 56 | }]; 57 | 58 | // Block to execute on alert dismissal 59 | [shakingAlert setOnDismissalWithoutPassword:^{ 60 | // Show regular UIAlertView to give them another go 61 | [self showFailedPasswordAlert]; 62 | 63 | }]; 64 | 65 | 66 | // Show and release 67 | [shakingAlert show]; 68 | 69 | } 70 | 71 | - (IBAction)md5LoginTaped:(id)sender { 72 | 73 | // Make the alert 74 | // Speficify we want to use MD5 hashing 75 | // Here we use a constructor that also takes the blocks 76 | ShakingAlertView *shakingAlert = [[ShakingAlertView alloc] 77 | initWithAlertTitle:@"Enter Password" 78 | checkForPassword:@"X03MO1qnZdYdgyfeuILPmQ==" //MD5 hash of 'password' 79 | usingHashingTechnique:HashTechniqueMD5 80 | onCorrectPassword:^{ 81 | // Show a modal view 82 | [self showModalView]; 83 | } 84 | onDismissalWithoutPassword:^{ 85 | // Show regular UIAlertView to give them another go 86 | [self showFailedPasswordAlert]; 87 | 88 | }]; 89 | 90 | 91 | // Show and release 92 | [shakingAlert show]; 93 | } 94 | 95 | #pragma mark - Others 96 | - (void)showModalView { 97 | 98 | ModalViewController *modalVC = nil; 99 | 100 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 101 | modalVC = [[ModalViewController alloc] initWithNibName:@"ModalViewController_iPhone" bundle:nil]; 102 | } else { 103 | modalVC = [[ModalViewController alloc] initWithNibName:@"ModalViewController_iPad" bundle:nil]; 104 | } 105 | 106 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:modalVC]; 107 | navController.modalPresentationStyle = UIModalPresentationFormSheet; 108 | 109 | [self presentModalViewController:navController animated:YES]; 110 | 111 | } 112 | 113 | - (void)showFailedPasswordAlert { 114 | UIAlertView *alert = [[UIAlertView alloc] 115 | initWithTitle:@"Failed Password Entry" 116 | message:@"To access the password protected view you must enter a valid password. Try again?" 117 | delegate:self 118 | cancelButtonTitle:@"No" 119 | otherButtonTitles:@"Yes", nil]; 120 | [alert show]; 121 | } 122 | 123 | #pragma mark - UIAlertViewDelegate 124 | 125 | - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 126 | 127 | // Give them another go at entering correct password 128 | if (buttonIndex != alertView.cancelButtonIndex) { 129 | [self plainTextLoginTapped:nil]; 130 | } 131 | } 132 | 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ShakingAlertView 2 | =================== 3 | 4 | [![Build Status](https://travis-ci.org/lukestringer90/ShakingAlertView.png?branch=master)](https://travis-ci.org/lukestringer90/ShakingAlertView) 5 | ![Pod version](http://cocoapod-badges.herokuapp.com/v/ShakingAlertView/badge.png) 6 | 7 | ShakingAlertView is a UIAlertView subclass with a password entry textfield. Incorrect password entry causes a "shake" animation similar to the OS X account login screen. 8 | 9 | ![screen](https://raw.github.com/lukestringer90/ShakingAlertView/master/screens/demo.gif) 10 | 11 | ## Installation 12 | ### Cocoapods 13 | Add to your Podfile: 14 | 15 | ``` 16 | pod 'ShakingAlertView' 17 | ``` 18 | 19 | ### Adding source code manually 20 | Clone the git repo and drag the **"src"** folder into your project. This contains the UI components and cryptographic helpers necessary for hashing passwords. 21 | 22 | ## Usage 23 | ### Plaintext password 24 | 25 | Use ShakingAlertView just like UIAlertView. For a checking a plain text password: 26 | 27 | ``` 28 | ShakingAlertView *shakingAlert = nil; 29 | shakingAlert = [[ShakingAlertView alloc] initWithAlertTitle:@"Enter Password" 30 | checkForPassword:@"pass"]; 31 | 32 | [shakingAlert setOnCorrectPassword:^{ 33 | // Code to execute on correct password entry 34 | }]; 35 | 36 | [shakingAlert setOnDismissalWithoutPassword:^{ 37 | // Code to execute on alert dismissal without password entry 38 | }]; 39 | 40 | [shakingAlert show]; 41 | ``` 42 | 43 | Rather than using a delegate, pass the instance a completion block to be executed for correct password entry and alert dismissal. ShakingAlertView uses ARC so no need to release your instances. 44 | 45 | ### Hashed passwords 46 | 47 | ShakingAlertView uses the [Common Crypto](https://developer.apple.com/library/mac/documentation/security/Conceptual/cryptoservices/GeneralPurposeCrypto/GeneralPurposeCrypto.html#//apple_ref/doc/uid/TP40011172-CH9-SW4) C API to hash the entered text to SHA1 or MD5. Therefore if you only know the hashed counterpart of a password string you can specify this along with the hashing algorithm type in the constructor. 48 | 49 | ``` 50 | ShakingAlertView *shakingAlert = nil; 51 | shakingAlert = [[ShakingAlertView alloc] initWithAlertTitle:@"Enter Password" 52 | checkForPassword:@"W6ph5Mm5Pz8GgiULbPgzG37mj9g=" //sha1 hash of 'password' 53 | usingHashingTechnique:HashTechniqueSHA1]; 54 | 55 | ``` 56 | 57 | The hashing algorithm to use is defined by an enum and passed into the constructor. 58 | ``` 59 | typedef enum { 60 | HashTechniqueNone, 61 | HashTechniqueSHA1, 62 | HashTechniqueMD5 63 | } HashTechnique; 64 | ``` 65 | 66 | `HashTechniqueNone` is used if no technique is specified, like in the `initWithAlertTitle:checkForPassword` and `initWithAlertTitle:checkForPassword:onCorrectPassword:onDismissalWithoutPassword` constructors. Here the entered string is compared with the specified plaintext password using a simple `isEqualToString:` evaluation. 67 | 68 | ## Running the tests 69 | The ShakingAlertView class is tested using the BDD tool [Kiwi](https://github.com/allending/Kiwi). To run the tests install Kiwi via [Cocoapods](http://cocoapods.org), and the open the workspace: 70 | 71 | ``` 72 | cd Example\ Project/ 73 | pod install 74 | open ExampleProject.xcworkspace/ 75 | ```` 76 | 77 | Make sure the **"ShakingAlertView"** scheme is selected then run the tests with **⌘+U** 78 | 79 | ## Acknowledgements 80 | `NSData+Base64.h/m` and `b64.h/m` from [aqtoolkit](https://github.com/AlanQuatermain/aqtoolkit) by [Jim Dovey](https://github.com/AlanQuatermain) 81 | 82 | [Kiwi](https://github.com/allending/Kiwi) testing tool. 83 | 84 | ## Licence 85 | This code is distributed under the terms and conditions of the MIT license. 86 | 87 | Copyright (c) 2012 Luke Stringer 88 | 89 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 90 | 91 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 92 | 93 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 94 | 95 | --- 96 | 97 | ### Author 98 | 99 | Follow me on twitter: [lukestringer90](http://twitter.com/lukestringer90) 100 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/ModalViewController_iPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1296 5 | 12B19 6 | 2549 7 | 1187 8 | 624.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1498 12 | 13 | 14 | IBProxyObject 15 | IBUILabel 16 | IBUIView 17 | 18 | 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | PluginDependencyRecalculationVersion 23 | 24 | 25 | 26 | 27 | IBFilesOwner 28 | IBCocoaTouchFramework 29 | 30 | 31 | IBFirstResponder 32 | IBCocoaTouchFramework 33 | 34 | 35 | 36 | 274 37 | 38 | 39 | 40 | 292 41 | {{64, 197}, {193, 21}} 42 | 43 | _NS:9 44 | NO 45 | YES 46 | 7 47 | NO 48 | IBCocoaTouchFramework 49 | Password protected view 50 | 51 | 1 52 | MCAwIDAAA 53 | 54 | 55 | 0 56 | 10 57 | 58 | 1 59 | 17 60 | 61 | 62 | Helvetica 63 | 17 64 | 16 65 | 66 | 67 | 68 | {{0, 64}, {320, 416}} 69 | 70 | 71 | 3 72 | MQA 73 | 74 | 2 75 | 76 | 77 | 78 | 79 | NO 80 | 81 | IBCocoaTouchFramework 82 | 83 | 84 | 85 | 86 | 87 | 88 | view 89 | 90 | 91 | 92 | 3 93 | 94 | 95 | 96 | 97 | 98 | 0 99 | 100 | 101 | 102 | 103 | 104 | 1 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -1 113 | 114 | 115 | File's Owner 116 | 117 | 118 | -2 119 | 120 | 121 | 122 | 123 | 4 124 | 125 | 126 | 127 | 128 | 129 | 130 | ModalViewController 131 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 132 | UIResponder 133 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 134 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 135 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 136 | 137 | 138 | 139 | 140 | 141 | 4 142 | 143 | 144 | 0 145 | IBCocoaTouchFramework 146 | 147 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 148 | 149 | 150 | YES 151 | 3 152 | 1498 153 | 154 | 155 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/ModalViewController_iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1296 5 | 12B19 6 | 2549 7 | 1187 8 | 624.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1498 12 | 13 | 14 | IBProxyObject 15 | IBUILabel 16 | IBUIView 17 | 18 | 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | PluginDependencyRecalculationVersion 23 | 24 | 25 | 26 | 27 | IBFilesOwner 28 | IBIPadFramework 29 | 30 | 31 | IBFirstResponder 32 | IBIPadFramework 33 | 34 | 35 | 36 | 274 37 | 38 | 39 | 40 | 292 41 | {{174, 267}, {193, 21}} 42 | 43 | _NS:9 44 | NO 45 | YES 46 | 7 47 | NO 48 | IBIPadFramework 49 | Password protected view 50 | 51 | 1 52 | MCAwIDAAA 53 | 54 | 55 | 0 56 | 10 57 | 58 | 1 59 | 17 60 | 61 | 62 | Helvetica 63 | 17 64 | 16 65 | 66 | 67 | 68 | {{0, 64}, {540, 556}} 69 | 70 | 71 | 72 | 3 73 | MQA 74 | 75 | 2 76 | 77 | 78 | 79 | 2 80 | 81 | 82 | NO 83 | 84 | 85 | IBUIModalFormSheetSimulatedSizeMetrics 86 | 87 | YES 88 | 89 | 90 | 91 | 92 | 93 | {540, 620} 94 | {540, 620} 95 | 96 | 97 | IBIPadFramework 98 | Form Sheet 99 | 100 | IBIPadFramework 101 | 102 | 103 | 104 | 105 | 106 | 107 | view 108 | 109 | 110 | 111 | 3 112 | 113 | 114 | 115 | 116 | 117 | 0 118 | 119 | 120 | 121 | 122 | 123 | -1 124 | 125 | 126 | File's Owner 127 | 128 | 129 | -2 130 | 131 | 132 | 133 | 134 | 2 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 8 143 | 144 | 145 | 146 | 147 | 148 | 149 | ModalViewController 150 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 151 | UIResponder 152 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 153 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 154 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 155 | 156 | 157 | 158 | 159 | 160 | 8 161 | 162 | 163 | 0 164 | IBIPadFramework 165 | 166 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 167 | 168 | 169 | YES 170 | 3 171 | 1498 172 | 173 | 174 | -------------------------------------------------------------------------------- /src/b64.m: -------------------------------------------------------------------------------- 1 | /* 2 | * b64.m 3 | * AQToolkit 4 | * 5 | * Created by Jim Dovey on 11-01-11. 6 | * Based on b64.c by Bob Trower 7 | * 8 | * 9 | */ 10 | /*********************************************************************\ 11 | 12 | MODULE NAME: b64.c 13 | 14 | AUTHOR: Bob Trower 08/04/01 15 | 16 | PROJECT: Crypt Data Packaging 17 | 18 | COPYRIGHT: Copyright (c) Trantor Standard Systems Inc., 2001 19 | 20 | NOTE: This source code may be used as you wish, subject to 21 | the MIT license. See the LICENCE section below. 22 | DESCRIPTION: 23 | This little utility implements the Base64 24 | Content-Transfer-Encoding standard described in 25 | RFC1113 (http://www.faqs.org/rfcs/rfc1113.html). 26 | 27 | This is the coding scheme used by MIME to allow 28 | binary data to be transferred by SMTP mail. 29 | 30 | Groups of 3 bytes from a binary stream are coded as 31 | groups of 4 bytes in a text stream. 32 | 33 | The input stream is 'padded' with zeros to create 34 | an input that is an even multiple of 3. 35 | 36 | A special character ('=') is used to denote padding so 37 | that the stream can be decoded back to its exact size. 38 | 39 | Encoded output is formatted in lines which should 40 | be a maximum of 72 characters to conform to the 41 | specification. This program defaults to 72 characters, 42 | but will allow more or less through the use of a 43 | switch. The program enforces a minimum line size 44 | of 4 characters. 45 | 46 | Example encoding: 47 | 48 | The stream 'ABCD' is 32 bits long. It is mapped as 49 | follows: 50 | 51 | ABCD 52 | 53 | A (65) B (66) C (67) D (68) (None) (None) 54 | 01000001 01000010 01000011 01000100 55 | 56 | 16 (Q) 20 (U) 9 (J) 3 (D) 17 (R) 0 (A) NA (=) NA (=) 57 | 010000 010100 001001 000011 010001 000000 000000 000000 58 | 59 | 60 | QUJDRA== 61 | 62 | Decoding is the process in reverse. A 'decode' lookup 63 | table has been created to avoid string scans. 64 | 65 | LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. 66 | 67 | Permission is hereby granted, free of charge, to any person 68 | obtaining a copy of this software and associated 69 | documentation files (the "Software"), to deal in the 70 | Software without restriction, including without limitation 71 | the rights to use, copy, modify, merge, publish, distribute, 72 | sublicense, and/or sell copies of the Software, and to 73 | permit persons to whom the Software is furnished to do so, 74 | subject to the following conditions: 75 | 76 | The above copyright notice and this permission notice shall 77 | be included in all copies or substantial portions of the 78 | Software. 79 | 80 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 81 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 82 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 83 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 84 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 85 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 86 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 87 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 88 | 89 | VERSION HISTORY: 90 | Bob Trower 08/04/01 -- Create Version 0.00.00B 91 | 92 | \******************************************************************* */ 93 | 94 | #import "b64.h" 95 | #import 96 | 97 | /* 98 | ** Translation Table as described in RFC1113 99 | */ 100 | static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 101 | 102 | /* 103 | ** Translation Table to decode (created by author) 104 | */ 105 | static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; 106 | 107 | /* 108 | ** encodeblock 109 | ** 110 | ** encode 3 8-bit binary bytes as 4 '6-bit' characters 111 | */ 112 | static void encodeblock( unsigned char in[3], unsigned char out[4], int len ) 113 | { 114 | out[0] = cb64[ in[0] >> 2 ]; 115 | out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; 116 | out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='); 117 | out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '='); 118 | } 119 | 120 | /* 121 | ** encode 122 | ** 123 | ** base64 encode a stream adding padding and line breaks as per spec. 124 | */ 125 | NSData * b64_encode( NSData * data ) 126 | { 127 | uint8_t in[3], out[4]; 128 | int i, len; 129 | 130 | const uint8_t *bytes = (const uint8_t *)[data bytes]; 131 | NSUInteger bytesLen = [data length]; 132 | NSUInteger offset = 0; 133 | 134 | NSMutableData * outputData = [[NSMutableData alloc] initWithCapacity: bytesLen + (bytesLen/4) + 1]; 135 | 136 | while( offset < bytesLen ) 137 | { 138 | len = 0; 139 | for( i = 0; i < 3; i++ ) 140 | { 141 | if ( offset < bytesLen ) 142 | { 143 | in[i] = bytes[offset++]; 144 | len++; 145 | } 146 | else 147 | { 148 | in[i] = 0; 149 | } 150 | } 151 | 152 | if ( len != 0 ) 153 | { 154 | encodeblock( in, out, len ); 155 | [outputData appendBytes: out length: 4]; 156 | } 157 | } 158 | 159 | NSData * result = [outputData copy]; 160 | return ( result ); 161 | } 162 | 163 | /* 164 | ** decodeblock 165 | ** 166 | ** decode 4 '6-bit' characters into 3 8-bit binary bytes 167 | */ 168 | void decodeblock( unsigned char in[4], unsigned char out[3] ) 169 | { 170 | out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4); 171 | out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2); 172 | out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]); 173 | } 174 | 175 | /* 176 | ** decode 177 | ** 178 | ** decode a base64 encoded stream discarding padding, line breaks and noise 179 | */ 180 | NSData * b64_decode( NSData * data ) 181 | { 182 | uint8_t in[4], out[3], v; 183 | int i, len; 184 | 185 | const uint8_t *bytes = (const uint8_t *)[data bytes]; 186 | NSUInteger bytesLen = [data length]; 187 | NSUInteger offset = 0; 188 | 189 | NSMutableData * outputData = [[NSMutableData alloc] initWithCapacity: bytesLen]; 190 | 191 | while ( offset < bytesLen ) 192 | { 193 | for ( len = 0, i = 0; i < 4 && offset < bytesLen; i++ ) 194 | { 195 | v = 0; 196 | while ( offset < bytesLen && v == 0 ) 197 | { 198 | v = bytes[offset++]; 199 | v = ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]); 200 | 201 | if ( v != 0 ) 202 | { 203 | v = ((v == '$') ? 0 : v - 61); 204 | } 205 | } 206 | 207 | if ( (offset < (bytesLen+1)) && (v != 0) ) 208 | { 209 | len++; 210 | if ( v != 0 ) 211 | { 212 | in[ i ] = (v - 1); 213 | } 214 | } 215 | else 216 | { 217 | in[i] = 0; 218 | } 219 | } 220 | 221 | if ( len ) 222 | { 223 | decodeblock( in, out ); 224 | [outputData appendBytes: out length: len-1]; 225 | } 226 | } 227 | 228 | NSData * result = [outputData copy]; 229 | return ( result ); 230 | } 231 | -------------------------------------------------------------------------------- /src/ShakingAlertView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShakingAlertView.m 3 | // 4 | // Created by Luke on 21/09/2012. 5 | // Copyright (c) 2012 Luke Stringer. All rights reserved. 6 | // 7 | // https://github.com/stringer630/ShakingAlertView 8 | // 9 | 10 | // This code is distributed under the terms and conditions of the MIT license. 11 | // 12 | // Copyright (c) 2012 Luke Stringer 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in 22 | // all copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | // THE SOFTWARE. 31 | 32 | #import "ShakingAlertView.h" 33 | #include 34 | #import "NSData+Base64.h" 35 | 36 | 37 | @interface ShakingAlertView () 38 | // Private property as other instances shouldn't interact with this directly 39 | @property (nonatomic, strong) UITextField *passwordField; 40 | @end 41 | 42 | // Enum for alert view button index 43 | typedef enum { 44 | ShakingAlertViewButtonIndexDismiss = 0, 45 | ShakingAlertViewButtonIndexSuccess = 10 46 | } ShakingAlertViewButtonIndex; 47 | 48 | @implementation ShakingAlertView 49 | 50 | #pragma mark - Constructors 51 | 52 | - (id)initWithAlertTitle:(NSString *)title 53 | checkForPassword:(NSString *)password{ 54 | 55 | self = [super initWithTitle:title 56 | message:@"---blank---" // password field will go here 57 | delegate:self 58 | cancelButtonTitle:@"Cancel" 59 | otherButtonTitles:@"Enter", nil]; 60 | if (self) { 61 | self.password = password; 62 | self.hashTechnique = HashTechniqueNone; // use no hashing by default 63 | } 64 | 65 | return self; 66 | } 67 | 68 | - (id)initWithAlertTitle:(NSString *)title 69 | checkForPassword:(NSString *)password 70 | onCorrectPassword:(void(^)())correctPasswordBlock 71 | onDismissalWithoutPassword:(void(^)())dismissalWithoutPasswordBlock { 72 | 73 | self = [self initWithAlertTitle:title checkForPassword:password]; 74 | if (self) { 75 | self.onCorrectPassword = correctPasswordBlock; 76 | self.onDismissalWithoutPassword = dismissalWithoutPasswordBlock; 77 | } 78 | 79 | 80 | return self; 81 | 82 | } 83 | 84 | - (id)initWithAlertTitle:(NSString *)title 85 | checkForPassword:(NSString *)password 86 | usingHashingTechnique:(HashTechnique)hashingTechnique { 87 | 88 | self = [self initWithAlertTitle:title checkForPassword:password]; 89 | if (self) { 90 | self.hashTechnique = hashingTechnique; 91 | } 92 | return self; 93 | 94 | } 95 | 96 | - (id)initWithAlertTitle:(NSString *)title 97 | checkForPassword:(NSString *)password 98 | usingHashingTechnique:(HashTechnique)hashingTechnique 99 | onCorrectPassword:(void(^)())correctPasswordBlock 100 | onDismissalWithoutPassword:(void(^)())dismissalWithoutPasswordBlock { 101 | 102 | 103 | self = [self initWithAlertTitle:title checkForPassword:password usingHashingTechnique:hashingTechnique]; 104 | if (self) { 105 | self.onCorrectPassword = correctPasswordBlock; 106 | self.onDismissalWithoutPassword = dismissalWithoutPasswordBlock; 107 | } 108 | 109 | 110 | return self; 111 | 112 | } 113 | 114 | // Override show method to add the password field 115 | - (void)show { 116 | 117 | // Textfield for the password 118 | // Position it over the message section of the alert 119 | UITextField *passwordField = [[UITextField alloc] initWithFrame:CGRectMake(14, 45, 256, 25)]; 120 | passwordField.secureTextEntry = YES; 121 | passwordField.placeholder = @"password"; 122 | passwordField.backgroundColor = [UIColor whiteColor]; 123 | 124 | // Pad out the left side of the view to properly inset the text 125 | UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 6, 19)]; 126 | passwordField.leftView = paddingView; 127 | passwordField.leftViewMode = UITextFieldViewModeAlways; 128 | 129 | // Set delegate 130 | passwordField.delegate = self; 131 | 132 | // Set as property 133 | self.passwordField = passwordField; 134 | 135 | // Add to subview 136 | [self addSubview:_passwordField]; 137 | 138 | // Show alert 139 | [super show]; 140 | 141 | // present keyboard for text entry 142 | [_passwordField performSelector:@selector(becomeFirstResponder) withObject:nil afterDelay:0.1]; 143 | 144 | } 145 | 146 | - (void)animateIncorrectPassword { 147 | // Clear the password field 148 | _passwordField.text = nil; 149 | 150 | // Animate the alert to show that the entered string was wrong 151 | // "Shakes" similar to OS X login screen 152 | CGAffineTransform moveRight = CGAffineTransformTranslate(CGAffineTransformIdentity, 20, 0); 153 | CGAffineTransform moveLeft = CGAffineTransformTranslate(CGAffineTransformIdentity, -20, 0); 154 | CGAffineTransform resetTransform = CGAffineTransformTranslate(CGAffineTransformIdentity, 0, 0); 155 | 156 | [UIView animateWithDuration:0.1 animations:^{ 157 | // Translate left 158 | self.transform = moveLeft; 159 | 160 | } completion:^(BOOL finished) { 161 | 162 | [UIView animateWithDuration:0.1 animations:^{ 163 | 164 | // Translate right 165 | self.transform = moveRight; 166 | 167 | } completion:^(BOOL finished) { 168 | 169 | [UIView animateWithDuration:0.1 animations:^{ 170 | 171 | // Translate left 172 | self.transform = moveLeft; 173 | 174 | } completion:^(BOOL finished) { 175 | 176 | [UIView animateWithDuration:0.1 animations:^{ 177 | 178 | // Translate to origin 179 | self.transform = resetTransform; 180 | }]; 181 | }]; 182 | 183 | }]; 184 | }]; 185 | 186 | } 187 | 188 | #pragma mark - UIAlertViewDelegate 189 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 190 | 191 | // If "Enter" button pressed on alert view then check password 192 | if (buttonIndex == alertView.firstOtherButtonIndex) { 193 | 194 | if ([self enteredTextIsCorrect]) { 195 | 196 | // Hide keyboard 197 | [self.passwordField resignFirstResponder]; 198 | 199 | // Dismiss with success 200 | [alertView dismissWithClickedButtonIndex:ShakingAlertViewButtonIndexSuccess animated:YES]; 201 | 202 | } 203 | 204 | // If incorrect then animate 205 | else { 206 | [self animateIncorrectPassword]; 207 | } 208 | } 209 | } 210 | 211 | 212 | // Overide to customise when alert is dimsissed 213 | - (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated { 214 | 215 | // Only dismiss for ShakingAlertViewButtonIndexDismiss or ShakingAlertViewButtonIndexSuccess 216 | // This means we don't dissmis for the case where "Enter" button is pressed and password is incorrect 217 | switch (buttonIndex) { 218 | case ShakingAlertViewButtonIndexSuccess: 219 | [super dismissWithClickedButtonIndex:ShakingAlertViewButtonIndexDismiss animated:animated]; 220 | [self safeCallBlock:self.onCorrectPassword]; 221 | break; 222 | case ShakingAlertViewButtonIndexDismiss: 223 | [super dismissWithClickedButtonIndex:ShakingAlertViewButtonIndexDismiss animated:animated]; 224 | [self safeCallBlock:self.onDismissalWithoutPassword]; 225 | break; 226 | default: 227 | break; 228 | } 229 | 230 | } 231 | 232 | #pragma mark - UITextFieldDelegate 233 | - (BOOL)textFieldShouldReturn:(UITextField *)textField { 234 | // Check password 235 | if ([self enteredTextIsCorrect]) { 236 | 237 | // Hide keyboard 238 | [self.passwordField resignFirstResponder]; 239 | 240 | // Dismiss with success 241 | [self dismissWithClickedButtonIndex:ShakingAlertViewButtonIndexSuccess animated:YES]; 242 | 243 | return YES; 244 | } 245 | 246 | // Password is incorrect to so animate 247 | [self animateIncorrectPassword]; 248 | return NO; 249 | } 250 | 251 | #pragma mark - Private helpers 252 | - (void)safeCallBlock:(void (^)(void))block { 253 | // Only call the block is not nil 254 | if (block) { 255 | block(); 256 | } 257 | } 258 | 259 | - (BOOL)enteredTextIsCorrect { 260 | switch (_hashTechnique) { 261 | 262 | // No hashing algorithm used 263 | case HashTechniqueNone: 264 | return [_passwordField.text isEqualToString:_password]; 265 | break; 266 | 267 | 268 | // SHA1 used 269 | case HashTechniqueSHA1: { 270 | 271 | unsigned char digest[CC_SHA1_DIGEST_LENGTH]; 272 | NSData *stringBytes = [_passwordField.text dataUsingEncoding: NSUTF8StringEncoding]; 273 | CC_SHA1([stringBytes bytes], [stringBytes length], digest); 274 | 275 | NSData *pwHashData = [[NSData alloc] initWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; 276 | NSString *hashedEnteredPassword = [pwHashData base64EncodedString]; 277 | 278 | return [hashedEnteredPassword isEqualToString:_password]; 279 | 280 | } 281 | break; 282 | 283 | 284 | // MD5 used 285 | case HashTechniqueMD5: { 286 | 287 | unsigned char digest[CC_MD5_DIGEST_LENGTH]; 288 | NSData *stringBytes = [_passwordField.text dataUsingEncoding: NSUTF8StringEncoding]; 289 | CC_MD5([stringBytes bytes], [stringBytes length], digest); 290 | 291 | NSData *pwHashData = [[NSData alloc] initWithBytes:digest length:CC_MD5_DIGEST_LENGTH]; 292 | NSString *hashedEnteredPassword = [pwHashData base64EncodedString]; 293 | 294 | return [hashedEnteredPassword isEqualToString:_password]; 295 | 296 | } 297 | break; 298 | 299 | default: 300 | break; 301 | } 302 | 303 | 304 | // To stop Xcode complaining return NO by default 305 | return NO; 306 | 307 | } 308 | 309 | #pragma mark - Memory Managment 310 | 311 | 312 | @end 313 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/en.lproj/ViewController_iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1296 5 | 12C54 6 | 2549 7 | 1187.34 8 | 625.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1498 12 | 13 | 14 | IBProxyObject 15 | IBUIButton 16 | IBUIView 17 | 18 | 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | PluginDependencyRecalculationVersion 23 | 24 | 25 | 26 | 27 | IBFilesOwner 28 | IBIPadFramework 29 | 30 | 31 | IBFirstResponder 32 | IBIPadFramework 33 | 34 | 35 | 36 | 274 37 | 38 | 39 | 40 | 292 41 | {{252, 366}, {265, 37}} 42 | 43 | 44 | 45 | _NS:9 46 | NO 47 | IBIPadFramework 48 | 0 49 | 0 50 | 1 51 | Access Password Protected View 52 | 53 | 3 54 | MQA 55 | 56 | 57 | 1 58 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 59 | 60 | 61 | 3 62 | MC41AA 63 | 64 | 65 | 2 66 | 15 67 | 68 | 69 | Helvetica-Bold 70 | 15 71 | 16 72 | 73 | 74 | 75 | 76 | 292 77 | {{252, 482}, {265, 37}} 78 | 79 | 80 | 81 | _NS:9 82 | NO 83 | IBIPadFramework 84 | 0 85 | 0 86 | 1 87 | Login With Plain SHA1 Password 88 | 89 | 90 | 1 91 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 292 100 | {{252, 590}, {265, 37}} 101 | 102 | 103 | 104 | _NS:9 105 | NO 106 | IBIPadFramework 107 | 0 108 | 0 109 | 1 110 | Login With Plain MD5 Password 111 | 112 | 113 | 1 114 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 115 | 116 | 117 | 118 | 119 | 120 | 121 | {{0, 20}, {768, 1004}} 122 | 123 | 124 | 125 | 126 | 3 127 | MQA 128 | 129 | 2 130 | 131 | 132 | 133 | 2 134 | 135 | IBIPadFramework 136 | 137 | 138 | 139 | 140 | 141 | 142 | view 143 | 144 | 145 | 146 | 3 147 | 148 | 149 | 150 | plainTextLoginTapped: 151 | 152 | 153 | 7 154 | 155 | 8 156 | 157 | 158 | 159 | sha1LoginTapped: 160 | 161 | 162 | 7 163 | 164 | 12 165 | 166 | 167 | 168 | md5LoginTaped: 169 | 170 | 171 | 7 172 | 173 | 11 174 | 175 | 176 | 177 | 178 | 179 | 0 180 | 181 | 182 | 183 | 184 | 185 | -1 186 | 187 | 188 | File's Owner 189 | 190 | 191 | -2 192 | 193 | 194 | 195 | 196 | 2 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 4 207 | 208 | 209 | 210 | 211 | 9 212 | 213 | 214 | 215 | 216 | 10 217 | 218 | 219 | 220 | 221 | 222 | 223 | ViewController 224 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 225 | UIResponder 226 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 227 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 228 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 229 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 230 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 231 | 232 | 233 | 234 | 235 | 236 | 12 237 | 238 | 239 | 240 | 241 | ViewController 242 | UIViewController 243 | 244 | id 245 | id 246 | id 247 | 248 | 249 | 250 | md5LoginTaped: 251 | id 252 | 253 | 254 | plainTextLoginTapped: 255 | id 256 | 257 | 258 | sha1LoginTapped: 259 | id 260 | 261 | 262 | 263 | IBProjectSource 264 | ./Classes/ViewController.h 265 | 266 | 267 | 268 | 269 | 0 270 | IBIPadFramework 271 | 272 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 273 | 274 | 275 | YES 276 | 3 277 | 1498 278 | 279 | 280 | -------------------------------------------------------------------------------- /Example Project/ExampleProject/en.lproj/ViewController_iPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1296 5 | 12C54 6 | 2549 7 | 1187.34 8 | 625.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1498 12 | 13 | 14 | IBProxyObject 15 | IBUIButton 16 | IBUIView 17 | 18 | 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | PluginDependencyRecalculationVersion 23 | 24 | 25 | 26 | 27 | IBFilesOwner 28 | IBCocoaTouchFramework 29 | 30 | 31 | IBFirstResponder 32 | IBCocoaTouchFramework 33 | 34 | 35 | 36 | 274 37 | 38 | 39 | 40 | 292 41 | {{28, 89}, {265, 37}} 42 | 43 | 44 | _NS:9 45 | NO 46 | IBCocoaTouchFramework 47 | 0 48 | 0 49 | 1 50 | Login With Plain Text Password 51 | 52 | 3 53 | MQA 54 | 55 | 56 | 1 57 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 58 | 59 | 60 | 3 61 | MC41AA 62 | 63 | 64 | 2 65 | 15 66 | 67 | 68 | Helvetica-Bold 69 | 15 70 | 16 71 | 72 | 73 | 74 | 75 | 292 76 | {{28, 211}, {265, 37}} 77 | 78 | 79 | _NS:9 80 | NO 81 | IBCocoaTouchFramework 82 | 0 83 | 0 84 | 1 85 | Login With Plain SHA1 Password 86 | 87 | 88 | 1 89 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 292 98 | {{28, 329}, {265, 37}} 99 | 100 | 101 | _NS:9 102 | NO 103 | IBCocoaTouchFramework 104 | 0 105 | 0 106 | 1 107 | Login With Plain MD5 Password 108 | 109 | 110 | 1 111 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 112 | 113 | 114 | 115 | 116 | 117 | 118 | {{0, 20}, {320, 460}} 119 | 120 | 121 | 122 | 123 | NO 124 | 125 | IBCocoaTouchFramework 126 | 127 | 128 | 129 | 292 130 | {72, 37} 131 | _NS:9 132 | NO 133 | IBCocoaTouchFramework 134 | 0 135 | 0 136 | 1 137 | 138 | 139 | 1 140 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | view 152 | 153 | 154 | 155 | 7 156 | 157 | 158 | 159 | plainTextLoginTapped: 160 | 161 | 162 | 7 163 | 164 | 18 165 | 166 | 167 | 168 | plainTextLoginTapped: 169 | 170 | 171 | 7 172 | 173 | 17 174 | 175 | 176 | 177 | md5LoginTaped: 178 | 179 | 180 | 7 181 | 182 | 21 183 | 184 | 185 | 186 | 187 | 188 | 0 189 | 190 | 191 | 192 | 193 | 194 | -1 195 | 196 | 197 | File's Owner 198 | 199 | 200 | -2 201 | 202 | 203 | 204 | 205 | 6 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 8 216 | 217 | 218 | 219 | 220 | 9 221 | 222 | 223 | 224 | 225 | 13 226 | 227 | 228 | 229 | 230 | 15 231 | 232 | 233 | 234 | 235 | 236 | 237 | ViewController 238 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 239 | UIResponder 240 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 241 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 242 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 243 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 244 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 245 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 246 | 247 | 248 | 249 | 250 | 251 | 21 252 | 253 | 254 | 255 | 256 | ViewController 257 | UIViewController 258 | 259 | id 260 | id 261 | id 262 | 263 | 264 | 265 | md5LoginTaped: 266 | id 267 | 268 | 269 | plainTextLoginTapped: 270 | id 271 | 272 | 273 | sha1LoginTapped: 274 | id 275 | 276 | 277 | 278 | IBProjectSource 279 | ./Classes/ViewController.h 280 | 281 | 282 | 283 | 284 | 0 285 | IBCocoaTouchFramework 286 | 287 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 288 | 289 | 290 | YES 291 | 3 292 | 1498 293 | 294 | 295 | -------------------------------------------------------------------------------- /Example Project/ShakingAlertViewKiwiTest/ShakingAlertViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShakingAlertViewTests.m 3 | // ExampleProject 4 | // 5 | // Created by Luke on 17/02/2013. 6 | // Copyright 2013 Luke Stringer. All rights reserved. 7 | // 8 | 9 | #import "Kiwi.h" 10 | #import "ShakingAlertView.h" 11 | 12 | // Mirror the class extension in ShakingAlertView.m so we can get to the private parts of the class 13 | @interface ShakingAlertView () 14 | @property (nonatomic, strong) UITextField *passwordField; 15 | - (void)animateIncorrectPassword; 16 | @end 17 | 18 | 19 | SPEC_BEGIN(ShakingAlertViewTests) 20 | 21 | describe(@"ShakingAlertView", ^{ 22 | 23 | context(@"construction", ^{ 24 | __block ShakingAlertView *shakingAlertView ; 25 | __block NSString *title; 26 | __block NSString *password; 27 | __block void (^correctPassword)(void); 28 | __block void (^dismissed)(void); 29 | 30 | beforeAll(^{ 31 | shakingAlertView = nil; 32 | title = @"Test Title"; 33 | password = @"password"; 34 | correctPassword = ^(void) { NSLog(@"Correct Password"); }; 35 | dismissed = ^(void) { NSLog(@"Dimssed"); }; 36 | }); 37 | 38 | afterEach(^{ 39 | shakingAlertView = nil; 40 | }); 41 | 42 | it(@"should not be nil for plaitext password", ^{ 43 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 44 | checkForPassword:password]; 45 | [shakingAlertView shouldNotBeNil]; 46 | }); 47 | 48 | it(@"should not be nil for plaintext password and completion blocks", ^{ 49 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 50 | checkForPassword:password 51 | onCorrectPassword:correctPassword 52 | onDismissalWithoutPassword:dismissed]; 53 | [shakingAlertView shouldNotBeNil]; 54 | }); 55 | 56 | it(@"should not be nil when using HashTechniqueNone ", ^{ 57 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 58 | checkForPassword:password 59 | usingHashingTechnique:HashTechniqueNone]; 60 | 61 | [shakingAlertView shouldNotBeNil]; 62 | 63 | }); 64 | 65 | it(@"should not be nil when using HashTechniqueSHA1 ", ^{ 66 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 67 | checkForPassword:password 68 | usingHashingTechnique:HashTechniqueSHA1]; 69 | 70 | [shakingAlertView shouldNotBeNil]; 71 | 72 | }); 73 | 74 | it(@"should not be nil when using HashTechniqueMD5 ", ^{ 75 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 76 | checkForPassword:password 77 | usingHashingTechnique:HashTechniqueMD5]; 78 | 79 | [shakingAlertView shouldNotBeNil]; 80 | 81 | }); 82 | 83 | it(@"should not be nil when using a HashTechnique and completion blocks", ^{ 84 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 85 | checkForPassword:password 86 | usingHashingTechnique:HashTechniqueMD5 87 | onCorrectPassword:correctPassword 88 | onDismissalWithoutPassword:dismissed]; 89 | 90 | [shakingAlertView shouldNotBeNil]; 91 | 92 | }); 93 | 94 | it(@"should use HashTechniqueNone by default", ^{ 95 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 96 | checkForPassword:password]; 97 | [[theValue(shakingAlertView.hashTechnique) should] equal:theValue(HashTechniqueNone)]; 98 | }); 99 | 100 | it(@"should return specified password property after construction", ^{ 101 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 102 | checkForPassword:password]; 103 | [[shakingAlertView.password should] equal:password]; 104 | }); 105 | 106 | it(@"should return specified title property after construction", ^{ 107 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 108 | checkForPassword:password]; 109 | [[shakingAlertView.title should] equal:title]; 110 | }); 111 | 112 | it(@"should return specified HashTechnique property after construction", ^{ 113 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 114 | checkForPassword:password usingHashingTechnique:HashTechniqueSHA1]; 115 | [[theValue(shakingAlertView.hashTechnique) should] equal:theValue(HashTechniqueSHA1)]; 116 | }); 117 | 118 | it(@"should have valid public properties after construction", ^{ 119 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 120 | checkForPassword:password 121 | usingHashingTechnique:HashTechniqueMD5 122 | onCorrectPassword:correctPassword 123 | onDismissalWithoutPassword:dismissed]; 124 | 125 | [shakingAlertView.title shouldNotBeNil]; 126 | [shakingAlertView.password shouldNotBeNil]; 127 | [shakingAlertView.onCorrectPassword shouldNotBeNil]; 128 | [shakingAlertView.onDismissalWithoutPassword shouldNotBeNil]; 129 | [theValue(shakingAlertView.hashTechnique) shouldNotBeNil]; 130 | 131 | }); 132 | 133 | }); 134 | // context end 135 | // ---------------------------------------------- 136 | 137 | context(@"alert view buttons tapped", ^{ 138 | __block ShakingAlertView *shakingAlertView; 139 | __block NSString *title; 140 | __block NSString *password; 141 | 142 | beforeAll(^{ 143 | shakingAlertView = nil; 144 | title = @"Test Title"; 145 | password = @"password"; 146 | }); 147 | 148 | afterEach(^{ 149 | shakingAlertView = nil; 150 | }); 151 | 152 | it(@"should succeed with button tap and call block for correct password entry", ^{ 153 | __block BOOL successReached = NO; 154 | __block BOOL failureReached = NO; 155 | __block int successReachedCount = 0; 156 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 157 | checkForPassword:password 158 | onCorrectPassword:^{ 159 | successReached = YES; 160 | successReachedCount++; 161 | } 162 | onDismissalWithoutPassword:^{ 163 | failureReached = YES; 164 | }]; 165 | [shakingAlertView show]; 166 | 167 | // Type and tap OK button 168 | shakingAlertView.passwordField.text = @"password"; 169 | [shakingAlertView.delegate alertView:shakingAlertView clickedButtonAtIndex:shakingAlertView.firstOtherButtonIndex]; 170 | 171 | // Success block should be called once, and failure should not be called at all 172 | [[theValue(successReached) should] beTrue]; 173 | [[theValue(failureReached) shouldNot] beTrue]; 174 | [[theValue(successReachedCount) should] equal:theValue(1)]; 175 | }); 176 | 177 | it(@"should fail with button tap and call block for incorrect password entry", ^{ 178 | __block BOOL successReached = NO; 179 | __block BOOL failureReached = NO; 180 | __block int failureReachedCount = 0; 181 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 182 | checkForPassword:password 183 | onCorrectPassword:^{ 184 | successReached = YES; 185 | } 186 | onDismissalWithoutPassword:^{ 187 | failureReached = YES; 188 | failureReachedCount++; 189 | }]; 190 | 191 | [shakingAlertView show]; 192 | 193 | // Dismiss it with cancel button 194 | [shakingAlertView dismissWithClickedButtonIndex:shakingAlertView.cancelButtonIndex animated:YES]; 195 | 196 | // Failure block should be called once, and sucess should not be called at all 197 | [[theValue(failureReached) should] beTrue]; 198 | [[theValue(successReached) shouldNot] beTrue]; 199 | [[theValue(failureReachedCount) should] equal:theValue(1)]; 200 | }); 201 | 202 | it(@"should shake with button for incorrect password entry", ^{ 203 | __block BOOL successReached = NO; 204 | __block BOOL failureReached = NO; 205 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 206 | checkForPassword:password onCorrectPassword:^{ 207 | successReached = YES; 208 | } onDismissalWithoutPassword:^{ 209 | failureReached = YES; 210 | }]; 211 | [shakingAlertView show]; 212 | 213 | // Type and tap return 214 | // Test the view shakes for the incorrect password 215 | shakingAlertView.passwordField.text = @"incorrect_password"; 216 | [[shakingAlertView should] receive:@selector(animateIncorrectPassword)]; 217 | [shakingAlertView.delegate alertView:shakingAlertView clickedButtonAtIndex:shakingAlertView.firstOtherButtonIndex]; 218 | 219 | // Neither of the completion blocks should have been called 220 | [[theValue(successReached) should] beFalse]; 221 | [[theValue(failureReached) should] beFalse]; 222 | }); 223 | }); 224 | // context end 225 | // ---------------------------------------------- 226 | 227 | context(@"return key tapped", ^{ 228 | __block ShakingAlertView *shakingAlertView; 229 | __block NSString *title; 230 | __block NSString *password; 231 | 232 | beforeAll(^{ 233 | shakingAlertView = nil; 234 | title = @"Test Title"; 235 | password = @"password"; 236 | }); 237 | 238 | afterEach(^{ 239 | shakingAlertView = nil; 240 | }); 241 | 242 | it(@"should succeed with return key and call block for correct password entry", ^{ 243 | __block BOOL successReached = NO; 244 | __block BOOL failureReached = NO; 245 | __block int successReachedCount = 0; 246 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 247 | checkForPassword:password 248 | onCorrectPassword:^{ 249 | successReached = YES; 250 | successReachedCount++; 251 | } 252 | onDismissalWithoutPassword:^{ 253 | failureReached = YES; 254 | }]; 255 | [shakingAlertView show]; 256 | 257 | // Type and tap return key 258 | shakingAlertView.passwordField.text = @"password"; 259 | [shakingAlertView textFieldShouldReturn:shakingAlertView.passwordField]; 260 | 261 | // Success block should be called once, and failure should not be called at all 262 | [[theValue(successReached) should] beTrue]; 263 | [[theValue(failureReached) shouldNot] beTrue]; 264 | [[theValue(successReachedCount) should] equal:theValue(1)]; 265 | }); 266 | 267 | 268 | it(@"should shake with return key for incorrect password entry", ^{ 269 | __block BOOL successReached = NO; 270 | __block BOOL failureReached = NO; 271 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 272 | checkForPassword:password onCorrectPassword:^{ 273 | successReached = YES; 274 | } onDismissalWithoutPassword:^{ 275 | failureReached = YES; 276 | }]; 277 | [shakingAlertView show]; 278 | 279 | // Type and tap return key 280 | // Test the view shakes for the incorrect password 281 | shakingAlertView.passwordField.text = @"incorrect_password"; 282 | [[shakingAlertView should] receive:@selector(animateIncorrectPassword)]; 283 | [shakingAlertView textFieldShouldReturn:shakingAlertView.passwordField]; 284 | 285 | // Neither of the completion blocks should have been called 286 | [[theValue(successReached) should] beFalse]; 287 | [[theValue(failureReached) should] beFalse]; 288 | }); 289 | }); 290 | 291 | // context end 292 | // ---------------------------------------------- 293 | 294 | context(@"SHA1 password checking", ^{ 295 | __block ShakingAlertView *shakingAlertView; 296 | __block NSString *title; 297 | __block NSString *SHA1Password; 298 | 299 | beforeAll(^{ 300 | shakingAlertView = nil; 301 | title = @"Test Title"; 302 | SHA1Password = @"W6ph5Mm5Pz8GgiULbPgzG37mj9g="; 303 | }); 304 | 305 | afterEach(^{ 306 | shakingAlertView = nil; 307 | }); 308 | 309 | it(@"should succeed and call block for correct password entry using SHA1", ^{ 310 | __block BOOL successReached = NO; 311 | __block BOOL failureReached = NO; 312 | __block int successReachedCount = 0; 313 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 314 | checkForPassword:SHA1Password 315 | usingHashingTechnique:HashTechniqueSHA1 316 | onCorrectPassword:^{ 317 | successReached = YES; 318 | successReachedCount++; 319 | } 320 | onDismissalWithoutPassword:^{ 321 | failureReached = YES; 322 | }]; 323 | 324 | [shakingAlertView show]; 325 | 326 | // Type and tap return key 327 | shakingAlertView.passwordField.text = @"password"; 328 | [shakingAlertView textFieldShouldReturn:shakingAlertView.passwordField]; 329 | 330 | // Success block should be called once, and failure should not be called at all 331 | [[theValue(successReached) should] beTrue]; 332 | [[theValue(failureReached) shouldNot] beTrue]; 333 | [[theValue(successReachedCount) should] equal:theValue(1)]; 334 | }); 335 | 336 | it(@"should fail and call block for incorrect password entry using SHA1", ^{ 337 | __block BOOL successReached = NO; 338 | __block BOOL failureReached = NO; 339 | __block int failureReachedCount = 0; 340 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 341 | checkForPassword:SHA1Password 342 | usingHashingTechnique:HashTechniqueSHA1 343 | onCorrectPassword:^{ 344 | successReached = YES; 345 | } 346 | onDismissalWithoutPassword:^{ 347 | failureReached = YES; 348 | failureReachedCount++; 349 | }]; 350 | 351 | [shakingAlertView show]; 352 | 353 | // Dismiss it with cancel button 354 | [shakingAlertView dismissWithClickedButtonIndex:shakingAlertView.cancelButtonIndex animated:YES]; 355 | 356 | // Failure block should be called once, and sucess should not be called at all 357 | [[theValue(failureReached) should] beTrue]; 358 | [[theValue(successReached) shouldNot] beTrue]; 359 | [[theValue(failureReachedCount) should] equal:theValue(1)]; 360 | }); 361 | 362 | it(@"should shake for incorrect password entry using SHA1", ^{ 363 | __block BOOL successReached = NO; 364 | __block BOOL failureReached = NO; 365 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 366 | checkForPassword:SHA1Password 367 | usingHashingTechnique:HashTechniqueSHA1 368 | onCorrectPassword:^{ 369 | successReached = YES; 370 | } onDismissalWithoutPassword:^{ 371 | failureReached = YES; 372 | }]; 373 | [shakingAlertView show]; 374 | 375 | // Type and tap return 376 | // Test the view shakes for the incorrect password 377 | shakingAlertView.passwordField.text = @"incorrect_password"; 378 | [[shakingAlertView should] receive:@selector(animateIncorrectPassword)]; 379 | [shakingAlertView.delegate alertView:shakingAlertView clickedButtonAtIndex:shakingAlertView.firstOtherButtonIndex]; 380 | 381 | // Neither of the completion blocks should have been called 382 | [[theValue(successReached) should] beFalse]; 383 | [[theValue(failureReached) should] beFalse]; 384 | }); 385 | 386 | 387 | }); 388 | // context end 389 | // ---------------------------------------------- 390 | 391 | context(@"MD5 password checking", ^{ 392 | __block ShakingAlertView *shakingAlertView; 393 | __block NSString *title; 394 | __block NSString *MD5Password; 395 | 396 | beforeAll(^{ 397 | shakingAlertView = nil; 398 | title = @"Test Title"; 399 | MD5Password = @"X03MO1qnZdYdgyfeuILPmQ=="; 400 | }); 401 | 402 | afterEach(^{ 403 | shakingAlertView = nil; 404 | }); 405 | 406 | it(@"should succeed and call block for correct password entry using MD5", ^{ 407 | __block BOOL successReached = NO; 408 | __block BOOL failureReached = NO; 409 | __block int successReachedCount = 0; 410 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 411 | checkForPassword:MD5Password 412 | usingHashingTechnique:HashTechniqueMD5 413 | onCorrectPassword:^{ 414 | successReached = YES; 415 | successReachedCount++; 416 | } 417 | onDismissalWithoutPassword:^{ 418 | failureReached = YES; 419 | }]; 420 | 421 | [shakingAlertView show]; 422 | 423 | // Type and tap return key 424 | shakingAlertView.passwordField.text = @"password"; 425 | [shakingAlertView textFieldShouldReturn:shakingAlertView.passwordField]; 426 | 427 | // Success block should be called once, and failure should not be called at all 428 | [[theValue(successReached) should] beTrue]; 429 | [[theValue(failureReached) shouldNot] beTrue]; 430 | [[theValue(successReachedCount) should] equal:theValue(1)]; 431 | }); 432 | 433 | it(@"should fail and call block for incorrect password entry using MD5", ^{ 434 | __block BOOL successReached = NO; 435 | __block BOOL failureReached = NO; 436 | __block int failureReachedCount = 0; 437 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 438 | checkForPassword:MD5Password 439 | usingHashingTechnique:HashTechniqueMD5 440 | onCorrectPassword:^{ 441 | successReached = YES; 442 | } 443 | onDismissalWithoutPassword:^{ 444 | failureReached = YES; 445 | failureReachedCount++; 446 | }]; 447 | 448 | [shakingAlertView show]; 449 | 450 | // Dismiss it with cancel button 451 | [shakingAlertView dismissWithClickedButtonIndex:shakingAlertView.cancelButtonIndex animated:YES]; 452 | 453 | // Failure block should be called once, and sucess should not be called at all 454 | [[theValue(failureReached) should] beTrue]; 455 | [[theValue(successReached) shouldNot] beTrue]; 456 | [[theValue(failureReachedCount) should] equal:theValue(1)]; 457 | }); 458 | 459 | it(@"should shake for incorrect password entry using MD5", ^{ 460 | __block BOOL successReached = NO; 461 | __block BOOL failureReached = NO; 462 | shakingAlertView = [[ShakingAlertView alloc] initWithAlertTitle:title 463 | checkForPassword:MD5Password 464 | usingHashingTechnique:HashTechniqueMD5 465 | onCorrectPassword:^{ 466 | successReached = YES; 467 | } onDismissalWithoutPassword:^{ 468 | failureReached = YES; 469 | }]; 470 | [shakingAlertView show]; 471 | 472 | // Type and tap return 473 | // Test the view shakes for the incorrect password 474 | shakingAlertView.passwordField.text = @"incorrect_password"; 475 | [[shakingAlertView should] receive:@selector(animateIncorrectPassword)]; 476 | [shakingAlertView.delegate alertView:shakingAlertView clickedButtonAtIndex:shakingAlertView.firstOtherButtonIndex]; 477 | 478 | // Neither of the completion blocks should have been called 479 | [[theValue(successReached) should] beFalse]; 480 | [[theValue(failureReached) should] beFalse]; 481 | }); 482 | 483 | 484 | }); 485 | // context end 486 | // ---------------------------------------------- 487 | 488 | }); 489 | 490 | SPEC_END 491 | 492 | 493 | -------------------------------------------------------------------------------- /Example Project/ExampleProject.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A33909D1160F17D80083C023 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A33909D0160F17D80083C023 /* UIKit.framework */; }; 11 | A33909D3160F17D80083C023 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A33909D2160F17D80083C023 /* Foundation.framework */; }; 12 | A33909D5160F17D80083C023 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A33909D4160F17D80083C023 /* CoreGraphics.framework */; }; 13 | A33909DB160F17D80083C023 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A33909D9160F17D80083C023 /* InfoPlist.strings */; }; 14 | A33909DD160F17D80083C023 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A33909DC160F17D80083C023 /* main.m */; }; 15 | A33909E1160F17D80083C023 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A33909E0160F17D80083C023 /* AppDelegate.m */; }; 16 | A33909E4160F17D80083C023 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A33909E3160F17D80083C023 /* ViewController.m */; }; 17 | A33909E7160F17D80083C023 /* ViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = A33909E5160F17D80083C023 /* ViewController_iPhone.xib */; }; 18 | A33909EA160F17D80083C023 /* ViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = A33909E8160F17D80083C023 /* ViewController_iPad.xib */; }; 19 | A33909F3160F18400083C023 /* ModalViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = A33909F0160F18400083C023 /* ModalViewController_iPhone.xib */; }; 20 | A33909F4160F18400083C023 /* ModalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A33909F2160F18400083C023 /* ModalViewController.m */; }; 21 | A33909F9160F18630083C023 /* ModalViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = A33909F8160F18630083C023 /* ModalViewController_iPad.xib */; }; 22 | A36DDF54171AE1C600E8DF1F /* b64.m in Sources */ = {isa = PBXBuildFile; fileRef = A36DDF51171AE1C600E8DF1F /* b64.m */; }; 23 | A36DDF55171AE1C600E8DF1F /* NSData+Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = A36DDF53171AE1C600E8DF1F /* NSData+Base64.m */; }; 24 | A36DDF58171AE1CE00E8DF1F /* ShakingAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = A36DDF57171AE1CE00E8DF1F /* ShakingAlertView.m */; }; 25 | A36DDF5A171AE5D500E8DF1F /* ShakingAlertViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A36DDF59171AE5D500E8DF1F /* ShakingAlertViewTests.m */; }; 26 | A3F40CD016D189F900E5FA63 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A3F40CCF16D189F900E5FA63 /* SenTestingKit.framework */; }; 27 | A3F40CD116D189F900E5FA63 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A33909D0160F17D80083C023 /* UIKit.framework */; }; 28 | A3F40CD216D189F900E5FA63 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A33909D2160F17D80083C023 /* Foundation.framework */; }; 29 | A3F40CD816D189F900E5FA63 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A3F40CD616D189F900E5FA63 /* InfoPlist.strings */; }; 30 | A3F40CE116D18B7500E5FA63 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A3F40CE016D18B7500E5FA63 /* Default-568h@2x.png */; }; 31 | F892AEBA08E346208C7BE4F5 /* libPods-ShakingAlertViewKiwiTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DEB572AA6B2D4A51BB4F3488 /* libPods-ShakingAlertViewKiwiTest.a */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXContainerItemProxy section */ 35 | A35C738816D198010069D9DF /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = A33909C3160F17D80083C023 /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = A33909CB160F17D80083C023; 40 | remoteInfo = ExampleProject; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 94B96CAED3054CEE8D07B941 /* Pods-ShakingAlertViewKiwiTest.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShakingAlertViewKiwiTest.xcconfig"; path = "Pods/Pods-ShakingAlertViewKiwiTest.xcconfig"; sourceTree = SOURCE_ROOT; }; 46 | A33909CC160F17D80083C023 /* ExampleProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | A33909D0160F17D80083C023 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 48 | A33909D2160F17D80083C023 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 49 | A33909D4160F17D80083C023 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 50 | A33909D8160F17D80083C023 /* ExampleProject-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ExampleProject-Info.plist"; sourceTree = ""; }; 51 | A33909DA160F17D80083C023 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 52 | A33909DC160F17D80083C023 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 53 | A33909DE160F17D80083C023 /* ExampleProject-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ExampleProject-Prefix.pch"; sourceTree = ""; }; 54 | A33909DF160F17D80083C023 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 55 | A33909E0160F17D80083C023 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 56 | A33909E2160F17D80083C023 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 57 | A33909E3160F17D80083C023 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 58 | A33909E6160F17D80083C023 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController_iPhone.xib; sourceTree = ""; }; 59 | A33909E9160F17D80083C023 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController_iPad.xib; sourceTree = ""; }; 60 | A33909F0160F18400083C023 /* ModalViewController_iPhone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ModalViewController_iPhone.xib; sourceTree = ""; }; 61 | A33909F1160F18400083C023 /* ModalViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalViewController.h; sourceTree = ""; }; 62 | A33909F2160F18400083C023 /* ModalViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalViewController.m; sourceTree = ""; }; 63 | A33909F8160F18630083C023 /* ModalViewController_iPad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ModalViewController_iPad.xib; sourceTree = ""; }; 64 | A36DDF50171AE1C600E8DF1F /* b64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = b64.h; path = ../../src/b64.h; sourceTree = ""; }; 65 | A36DDF51171AE1C600E8DF1F /* b64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = b64.m; path = ../../src/b64.m; sourceTree = ""; }; 66 | A36DDF52171AE1C600E8DF1F /* NSData+Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+Base64.h"; path = "../../src/NSData+Base64.h"; sourceTree = ""; }; 67 | A36DDF53171AE1C600E8DF1F /* NSData+Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+Base64.m"; path = "../../src/NSData+Base64.m"; sourceTree = ""; }; 68 | A36DDF56171AE1CE00E8DF1F /* ShakingAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ShakingAlertView.h; path = ../../src/ShakingAlertView.h; sourceTree = ""; }; 69 | A36DDF57171AE1CE00E8DF1F /* ShakingAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ShakingAlertView.m; path = ../../src/ShakingAlertView.m; sourceTree = ""; }; 70 | A36DDF59171AE5D500E8DF1F /* ShakingAlertViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShakingAlertViewTests.m; sourceTree = ""; }; 71 | A3F40CCE16D189F900E5FA63 /* ShakingAlertViewKiwiTest.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ShakingAlertViewKiwiTest.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | A3F40CCF16D189F900E5FA63 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 73 | A3F40CD516D189F900E5FA63 /* ShakingAlertViewKiwiTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ShakingAlertViewKiwiTest-Info.plist"; sourceTree = ""; }; 74 | A3F40CD716D189F900E5FA63 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 75 | A3F40CDC16D189F900E5FA63 /* ShakingAlertViewKiwiTest-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ShakingAlertViewKiwiTest-Prefix.pch"; sourceTree = ""; }; 76 | A3F40CE016D18B7500E5FA63 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 77 | DEB572AA6B2D4A51BB4F3488 /* libPods-ShakingAlertViewKiwiTest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ShakingAlertViewKiwiTest.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | /* End PBXFileReference section */ 79 | 80 | /* Begin PBXFrameworksBuildPhase section */ 81 | A33909C9160F17D80083C023 /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | A33909D1160F17D80083C023 /* UIKit.framework in Frameworks */, 86 | A33909D3160F17D80083C023 /* Foundation.framework in Frameworks */, 87 | A33909D5160F17D80083C023 /* CoreGraphics.framework in Frameworks */, 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | A3F40CCA16D189F900E5FA63 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | A3F40CD016D189F900E5FA63 /* SenTestingKit.framework in Frameworks */, 96 | A3F40CD116D189F900E5FA63 /* UIKit.framework in Frameworks */, 97 | A3F40CD216D189F900E5FA63 /* Foundation.framework in Frameworks */, 98 | F892AEBA08E346208C7BE4F5 /* libPods-ShakingAlertViewKiwiTest.a in Frameworks */, 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | /* End PBXFrameworksBuildPhase section */ 103 | 104 | /* Begin PBXGroup section */ 105 | A33909C1160F17D80083C023 = { 106 | isa = PBXGroup; 107 | children = ( 108 | A3F40CE016D18B7500E5FA63 /* Default-568h@2x.png */, 109 | A33909D6160F17D80083C023 /* ExampleProject */, 110 | A3F40CD316D189F900E5FA63 /* ShakingAlertViewKiwiTest */, 111 | A33909CF160F17D80083C023 /* Frameworks */, 112 | A33909CD160F17D80083C023 /* Products */, 113 | 94B96CAED3054CEE8D07B941 /* Pods-ShakingAlertViewKiwiTest.xcconfig */, 114 | ); 115 | sourceTree = ""; 116 | }; 117 | A33909CD160F17D80083C023 /* Products */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | A33909CC160F17D80083C023 /* ExampleProject.app */, 121 | A3F40CCE16D189F900E5FA63 /* ShakingAlertViewKiwiTest.octest */, 122 | ); 123 | name = Products; 124 | sourceTree = ""; 125 | }; 126 | A33909CF160F17D80083C023 /* Frameworks */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | A33909D0160F17D80083C023 /* UIKit.framework */, 130 | A33909D2160F17D80083C023 /* Foundation.framework */, 131 | A33909D4160F17D80083C023 /* CoreGraphics.framework */, 132 | A3F40CCF16D189F900E5FA63 /* SenTestingKit.framework */, 133 | DEB572AA6B2D4A51BB4F3488 /* libPods-ShakingAlertViewKiwiTest.a */, 134 | ); 135 | name = Frameworks; 136 | sourceTree = ""; 137 | }; 138 | A33909D6160F17D80083C023 /* ExampleProject */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | A33909DF160F17D80083C023 /* AppDelegate.h */, 142 | A33909E0160F17D80083C023 /* AppDelegate.m */, 143 | A33909FC160F18990083C023 /* ShakingAlertView */, 144 | A33909FB160F18920083C023 /* View Controllers */, 145 | A33909FA160F18850083C023 /* XIB */, 146 | A33909D7160F17D80083C023 /* Supporting Files */, 147 | ); 148 | path = ExampleProject; 149 | sourceTree = ""; 150 | }; 151 | A33909D7160F17D80083C023 /* Supporting Files */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | A33909D8160F17D80083C023 /* ExampleProject-Info.plist */, 155 | A33909D9160F17D80083C023 /* InfoPlist.strings */, 156 | A33909DC160F17D80083C023 /* main.m */, 157 | A33909DE160F17D80083C023 /* ExampleProject-Prefix.pch */, 158 | ); 159 | name = "Supporting Files"; 160 | sourceTree = ""; 161 | }; 162 | A33909FA160F18850083C023 /* XIB */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | A33909E5160F17D80083C023 /* ViewController_iPhone.xib */, 166 | A33909E8160F17D80083C023 /* ViewController_iPad.xib */, 167 | A33909F0160F18400083C023 /* ModalViewController_iPhone.xib */, 168 | A33909F8160F18630083C023 /* ModalViewController_iPad.xib */, 169 | ); 170 | name = XIB; 171 | sourceTree = ""; 172 | }; 173 | A33909FB160F18920083C023 /* View Controllers */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | A33909E2160F17D80083C023 /* ViewController.h */, 177 | A33909E3160F17D80083C023 /* ViewController.m */, 178 | A33909F1160F18400083C023 /* ModalViewController.h */, 179 | A33909F2160F18400083C023 /* ModalViewController.m */, 180 | ); 181 | name = "View Controllers"; 182 | sourceTree = ""; 183 | }; 184 | A33909FC160F18990083C023 /* ShakingAlertView */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | A36DDF56171AE1CE00E8DF1F /* ShakingAlertView.h */, 188 | A36DDF57171AE1CE00E8DF1F /* ShakingAlertView.m */, 189 | A3E0B6C5160F4555001E7952 /* Crypt */, 190 | ); 191 | name = ShakingAlertView; 192 | sourceTree = ""; 193 | }; 194 | A3E0B6C5160F4555001E7952 /* Crypt */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | A36DDF50171AE1C600E8DF1F /* b64.h */, 198 | A36DDF51171AE1C600E8DF1F /* b64.m */, 199 | A36DDF52171AE1C600E8DF1F /* NSData+Base64.h */, 200 | A36DDF53171AE1C600E8DF1F /* NSData+Base64.m */, 201 | ); 202 | name = Crypt; 203 | sourceTree = ""; 204 | }; 205 | A3F40CD316D189F900E5FA63 /* ShakingAlertViewKiwiTest */ = { 206 | isa = PBXGroup; 207 | children = ( 208 | A36DDF59171AE5D500E8DF1F /* ShakingAlertViewTests.m */, 209 | A3F40CD416D189F900E5FA63 /* Supporting Files */, 210 | ); 211 | path = ShakingAlertViewKiwiTest; 212 | sourceTree = ""; 213 | }; 214 | A3F40CD416D189F900E5FA63 /* Supporting Files */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | A3F40CD516D189F900E5FA63 /* ShakingAlertViewKiwiTest-Info.plist */, 218 | A3F40CD616D189F900E5FA63 /* InfoPlist.strings */, 219 | A3F40CDC16D189F900E5FA63 /* ShakingAlertViewKiwiTest-Prefix.pch */, 220 | ); 221 | name = "Supporting Files"; 222 | sourceTree = ""; 223 | }; 224 | /* End PBXGroup section */ 225 | 226 | /* Begin PBXNativeTarget section */ 227 | A33909CB160F17D80083C023 /* ExampleProject */ = { 228 | isa = PBXNativeTarget; 229 | buildConfigurationList = A33909ED160F17D80083C023 /* Build configuration list for PBXNativeTarget "ExampleProject" */; 230 | buildPhases = ( 231 | A33909C8160F17D80083C023 /* Sources */, 232 | A33909C9160F17D80083C023 /* Frameworks */, 233 | A33909CA160F17D80083C023 /* Resources */, 234 | ); 235 | buildRules = ( 236 | ); 237 | dependencies = ( 238 | ); 239 | name = ExampleProject; 240 | productName = ExampleProject; 241 | productReference = A33909CC160F17D80083C023 /* ExampleProject.app */; 242 | productType = "com.apple.product-type.application"; 243 | }; 244 | A3F40CCD16D189F900E5FA63 /* ShakingAlertViewKiwiTest */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = A3F40CDD16D189F900E5FA63 /* Build configuration list for PBXNativeTarget "ShakingAlertViewKiwiTest" */; 247 | buildPhases = ( 248 | A3F40CC916D189F900E5FA63 /* Sources */, 249 | A3F40CCA16D189F900E5FA63 /* Frameworks */, 250 | A3F40CCB16D189F900E5FA63 /* Resources */, 251 | A3F40CCC16D189F900E5FA63 /* ShellScript */, 252 | 50CE85E8BB0340788216EDCA /* Copy Pods Resources */, 253 | ); 254 | buildRules = ( 255 | ); 256 | dependencies = ( 257 | A35C738916D198010069D9DF /* PBXTargetDependency */, 258 | ); 259 | name = ShakingAlertViewKiwiTest; 260 | productName = ShakingAlertViewKiwiTest; 261 | productReference = A3F40CCE16D189F900E5FA63 /* ShakingAlertViewKiwiTest.octest */; 262 | productType = "com.apple.product-type.bundle"; 263 | }; 264 | /* End PBXNativeTarget section */ 265 | 266 | /* Begin PBXProject section */ 267 | A33909C3160F17D80083C023 /* Project object */ = { 268 | isa = PBXProject; 269 | attributes = { 270 | LastUpgradeCheck = 0460; 271 | ORGANIZATIONNAME = "Luke Stringer"; 272 | }; 273 | buildConfigurationList = A33909C6160F17D80083C023 /* Build configuration list for PBXProject "ExampleProject" */; 274 | compatibilityVersion = "Xcode 3.2"; 275 | developmentRegion = English; 276 | hasScannedForEncodings = 0; 277 | knownRegions = ( 278 | en, 279 | ); 280 | mainGroup = A33909C1160F17D80083C023; 281 | productRefGroup = A33909CD160F17D80083C023 /* Products */; 282 | projectDirPath = ""; 283 | projectRoot = ""; 284 | targets = ( 285 | A33909CB160F17D80083C023 /* ExampleProject */, 286 | A3F40CCD16D189F900E5FA63 /* ShakingAlertViewKiwiTest */, 287 | ); 288 | }; 289 | /* End PBXProject section */ 290 | 291 | /* Begin PBXResourcesBuildPhase section */ 292 | A33909CA160F17D80083C023 /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | A33909DB160F17D80083C023 /* InfoPlist.strings in Resources */, 297 | A33909E7160F17D80083C023 /* ViewController_iPhone.xib in Resources */, 298 | A33909EA160F17D80083C023 /* ViewController_iPad.xib in Resources */, 299 | A33909F3160F18400083C023 /* ModalViewController_iPhone.xib in Resources */, 300 | A33909F9160F18630083C023 /* ModalViewController_iPad.xib in Resources */, 301 | A3F40CE116D18B7500E5FA63 /* Default-568h@2x.png in Resources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | A3F40CCB16D189F900E5FA63 /* Resources */ = { 306 | isa = PBXResourcesBuildPhase; 307 | buildActionMask = 2147483647; 308 | files = ( 309 | A3F40CD816D189F900E5FA63 /* InfoPlist.strings in Resources */, 310 | ); 311 | runOnlyForDeploymentPostprocessing = 0; 312 | }; 313 | /* End PBXResourcesBuildPhase section */ 314 | 315 | /* Begin PBXShellScriptBuildPhase section */ 316 | 50CE85E8BB0340788216EDCA /* Copy Pods Resources */ = { 317 | isa = PBXShellScriptBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | ); 321 | inputPaths = ( 322 | ); 323 | name = "Copy Pods Resources"; 324 | outputPaths = ( 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | shellPath = /bin/sh; 328 | shellScript = "\"${SRCROOT}/Pods/Pods-ShakingAlertViewKiwiTest-resources.sh\"\n"; 329 | }; 330 | A3F40CCC16D189F900E5FA63 /* ShellScript */ = { 331 | isa = PBXShellScriptBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | ); 335 | inputPaths = ( 336 | ); 337 | outputPaths = ( 338 | ); 339 | runOnlyForDeploymentPostprocessing = 0; 340 | shellPath = /bin/sh; 341 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 342 | }; 343 | /* End PBXShellScriptBuildPhase section */ 344 | 345 | /* Begin PBXSourcesBuildPhase section */ 346 | A33909C8160F17D80083C023 /* Sources */ = { 347 | isa = PBXSourcesBuildPhase; 348 | buildActionMask = 2147483647; 349 | files = ( 350 | A33909DD160F17D80083C023 /* main.m in Sources */, 351 | A33909E1160F17D80083C023 /* AppDelegate.m in Sources */, 352 | A33909E4160F17D80083C023 /* ViewController.m in Sources */, 353 | A33909F4160F18400083C023 /* ModalViewController.m in Sources */, 354 | A36DDF54171AE1C600E8DF1F /* b64.m in Sources */, 355 | A36DDF55171AE1C600E8DF1F /* NSData+Base64.m in Sources */, 356 | A36DDF58171AE1CE00E8DF1F /* ShakingAlertView.m in Sources */, 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | A3F40CC916D189F900E5FA63 /* Sources */ = { 361 | isa = PBXSourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | A36DDF5A171AE5D500E8DF1F /* ShakingAlertViewTests.m in Sources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | /* End PBXSourcesBuildPhase section */ 369 | 370 | /* Begin PBXTargetDependency section */ 371 | A35C738916D198010069D9DF /* PBXTargetDependency */ = { 372 | isa = PBXTargetDependency; 373 | target = A33909CB160F17D80083C023 /* ExampleProject */; 374 | targetProxy = A35C738816D198010069D9DF /* PBXContainerItemProxy */; 375 | }; 376 | /* End PBXTargetDependency section */ 377 | 378 | /* Begin PBXVariantGroup section */ 379 | A33909D9160F17D80083C023 /* InfoPlist.strings */ = { 380 | isa = PBXVariantGroup; 381 | children = ( 382 | A33909DA160F17D80083C023 /* en */, 383 | ); 384 | name = InfoPlist.strings; 385 | sourceTree = ""; 386 | }; 387 | A33909E5160F17D80083C023 /* ViewController_iPhone.xib */ = { 388 | isa = PBXVariantGroup; 389 | children = ( 390 | A33909E6160F17D80083C023 /* en */, 391 | ); 392 | name = ViewController_iPhone.xib; 393 | sourceTree = ""; 394 | }; 395 | A33909E8160F17D80083C023 /* ViewController_iPad.xib */ = { 396 | isa = PBXVariantGroup; 397 | children = ( 398 | A33909E9160F17D80083C023 /* en */, 399 | ); 400 | name = ViewController_iPad.xib; 401 | sourceTree = ""; 402 | }; 403 | A3F40CD616D189F900E5FA63 /* InfoPlist.strings */ = { 404 | isa = PBXVariantGroup; 405 | children = ( 406 | A3F40CD716D189F900E5FA63 /* en */, 407 | ); 408 | name = InfoPlist.strings; 409 | sourceTree = ""; 410 | }; 411 | /* End PBXVariantGroup section */ 412 | 413 | /* Begin XCBuildConfiguration section */ 414 | A33909EB160F17D80083C023 /* Debug */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | ALWAYS_SEARCH_USER_PATHS = NO; 418 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 419 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 420 | CLANG_WARN_CONSTANT_CONVERSION = YES; 421 | CLANG_WARN_ENUM_CONVERSION = YES; 422 | CLANG_WARN_INT_CONVERSION = YES; 423 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 424 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 425 | COPY_PHASE_STRIP = NO; 426 | GCC_C_LANGUAGE_STANDARD = gnu99; 427 | GCC_DYNAMIC_NO_PIC = NO; 428 | GCC_OPTIMIZATION_LEVEL = 0; 429 | GCC_PREPROCESSOR_DEFINITIONS = ( 430 | "DEBUG=1", 431 | "$(inherited)", 432 | ); 433 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 434 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 435 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 436 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 437 | GCC_WARN_UNUSED_VARIABLE = YES; 438 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 439 | SDKROOT = iphoneos; 440 | TARGETED_DEVICE_FAMILY = "1,2"; 441 | }; 442 | name = Debug; 443 | }; 444 | A33909EC160F17D80083C023 /* Release */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | ALWAYS_SEARCH_USER_PATHS = NO; 448 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 450 | CLANG_WARN_CONSTANT_CONVERSION = YES; 451 | CLANG_WARN_ENUM_CONVERSION = YES; 452 | CLANG_WARN_INT_CONVERSION = YES; 453 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 454 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 455 | COPY_PHASE_STRIP = YES; 456 | GCC_C_LANGUAGE_STANDARD = gnu99; 457 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 458 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 459 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 460 | GCC_WARN_UNUSED_VARIABLE = YES; 461 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 462 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 463 | SDKROOT = iphoneos; 464 | TARGETED_DEVICE_FAMILY = "1,2"; 465 | VALIDATE_PRODUCT = YES; 466 | }; 467 | name = Release; 468 | }; 469 | A33909EE160F17D80083C023 /* Debug */ = { 470 | isa = XCBuildConfiguration; 471 | buildSettings = { 472 | CLANG_ENABLE_OBJC_ARC = YES; 473 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 474 | GCC_PREFIX_HEADER = "ExampleProject/ExampleProject-Prefix.pch"; 475 | INFOPLIST_FILE = "ExampleProject/ExampleProject-Info.plist"; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | WRAPPER_EXTENSION = app; 478 | }; 479 | name = Debug; 480 | }; 481 | A33909EF160F17D80083C023 /* Release */ = { 482 | isa = XCBuildConfiguration; 483 | buildSettings = { 484 | CLANG_ENABLE_OBJC_ARC = YES; 485 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 486 | GCC_PREFIX_HEADER = "ExampleProject/ExampleProject-Prefix.pch"; 487 | INFOPLIST_FILE = "ExampleProject/ExampleProject-Info.plist"; 488 | PRODUCT_NAME = "$(TARGET_NAME)"; 489 | WRAPPER_EXTENSION = app; 490 | }; 491 | name = Release; 492 | }; 493 | A3F40CDE16D189F900E5FA63 /* Debug */ = { 494 | isa = XCBuildConfiguration; 495 | baseConfigurationReference = 94B96CAED3054CEE8D07B941 /* Pods-ShakingAlertViewKiwiTest.xcconfig */; 496 | buildSettings = { 497 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ExampleProject.app/ExampleProject"; 498 | CLANG_CXX_LIBRARY = "libc++"; 499 | CLANG_ENABLE_OBJC_ARC = YES; 500 | CLANG_WARN_CONSTANT_CONVERSION = YES; 501 | CLANG_WARN_EMPTY_BODY = YES; 502 | CLANG_WARN_ENUM_CONVERSION = YES; 503 | CLANG_WARN_INT_CONVERSION = YES; 504 | FRAMEWORK_SEARCH_PATHS = ( 505 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 506 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 507 | ); 508 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 509 | GCC_PREFIX_HEADER = "ShakingAlertViewKiwiTest/ShakingAlertViewKiwiTest-Prefix.pch"; 510 | INFOPLIST_FILE = "ShakingAlertViewKiwiTest/ShakingAlertViewKiwiTest-Info.plist"; 511 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 512 | ONLY_ACTIVE_ARCH = YES; 513 | PRODUCT_NAME = "$(TARGET_NAME)"; 514 | TEST_HOST = "$(BUNDLE_LOADER)"; 515 | WRAPPER_EXTENSION = octest; 516 | }; 517 | name = Debug; 518 | }; 519 | A3F40CDF16D189F900E5FA63 /* Release */ = { 520 | isa = XCBuildConfiguration; 521 | baseConfigurationReference = 94B96CAED3054CEE8D07B941 /* Pods-ShakingAlertViewKiwiTest.xcconfig */; 522 | buildSettings = { 523 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ExampleProject.app/ExampleProject"; 524 | CLANG_CXX_LIBRARY = "libc++"; 525 | CLANG_ENABLE_OBJC_ARC = YES; 526 | CLANG_WARN_CONSTANT_CONVERSION = YES; 527 | CLANG_WARN_EMPTY_BODY = YES; 528 | CLANG_WARN_ENUM_CONVERSION = YES; 529 | CLANG_WARN_INT_CONVERSION = YES; 530 | FRAMEWORK_SEARCH_PATHS = ( 531 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 532 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 533 | ); 534 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 535 | GCC_PREFIX_HEADER = "ShakingAlertViewKiwiTest/ShakingAlertViewKiwiTest-Prefix.pch"; 536 | INFOPLIST_FILE = "ShakingAlertViewKiwiTest/ShakingAlertViewKiwiTest-Info.plist"; 537 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 538 | PRODUCT_NAME = "$(TARGET_NAME)"; 539 | TEST_HOST = "$(BUNDLE_LOADER)"; 540 | WRAPPER_EXTENSION = octest; 541 | }; 542 | name = Release; 543 | }; 544 | /* End XCBuildConfiguration section */ 545 | 546 | /* Begin XCConfigurationList section */ 547 | A33909C6160F17D80083C023 /* Build configuration list for PBXProject "ExampleProject" */ = { 548 | isa = XCConfigurationList; 549 | buildConfigurations = ( 550 | A33909EB160F17D80083C023 /* Debug */, 551 | A33909EC160F17D80083C023 /* Release */, 552 | ); 553 | defaultConfigurationIsVisible = 0; 554 | defaultConfigurationName = Release; 555 | }; 556 | A33909ED160F17D80083C023 /* Build configuration list for PBXNativeTarget "ExampleProject" */ = { 557 | isa = XCConfigurationList; 558 | buildConfigurations = ( 559 | A33909EE160F17D80083C023 /* Debug */, 560 | A33909EF160F17D80083C023 /* Release */, 561 | ); 562 | defaultConfigurationIsVisible = 0; 563 | defaultConfigurationName = Release; 564 | }; 565 | A3F40CDD16D189F900E5FA63 /* Build configuration list for PBXNativeTarget "ShakingAlertViewKiwiTest" */ = { 566 | isa = XCConfigurationList; 567 | buildConfigurations = ( 568 | A3F40CDE16D189F900E5FA63 /* Debug */, 569 | A3F40CDF16D189F900E5FA63 /* Release */, 570 | ); 571 | defaultConfigurationIsVisible = 0; 572 | defaultConfigurationName = Release; 573 | }; 574 | /* End XCConfigurationList section */ 575 | }; 576 | rootObject = A33909C3160F17D80083C023 /* Project object */; 577 | } 578 | --------------------------------------------------------------------------------