Merge pull request #1 from google/develop

Adds workspace, updates jazzy and travis config.
diff --git a/.jazzy.yaml b/.jazzy.yaml
index 48db303..50f4700 100644
--- a/.jazzy.yaml
+++ b/.jazzy.yaml
@@ -1,4 +1,4 @@
 module_name: GOSSpritedAnimationView
 umbrella_header: src/GOSSpritedAnimationView.h
-objc_mode: true
+objc: true
 sdk: iphonesimulator
diff --git a/.travis.yml b/.travis.yml
index 7245044..800bc03 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,23 +1,24 @@
 language: objective-c
-osx_image: xcode7.1
+osx_image: xcode7.2
 sudo: false
+notifications:
+  email: false
 env:
   global:
   - LC_CTYPE=en_US.UTF-8
   - LANG=en_US.UTF-8
   matrix:
-    - DESTINATION="OS=9.1,name=iPhone 6s" SDK=iphonesimulator9.1
-    - DESTINATION="OS=9.0,name=iPhone 6 Plus" SDK=iphonesimulator9.1
-    - DESTINATION="OS=8.4,name=iPhone 6" SDK=iphonesimulator9.1
-    - DESTINATION="OS=8.3,name=iPhone 5S" SDK=iphonesimulator9.1
-    - DESTINATION="OS=8.2,name=iPhone 5" SDK=iphonesimulator9.1
-    - DESTINATION="OS=8.1,name=iPhone 4S" SDK=iphonesimulator9.1
+    - DESTINATION="OS=9.2,name=iPhone 6 Plus" SDK=iphonesimulator9.2
+    - DESTINATION="OS=9.1,name=iPhone 6s" SDK=iphonesimulator9.2
+    - DESTINATION="OS=9.0,name=iPhone 6 Plus" SDK=iphonesimulator9.2
+    - DESTINATION="OS=8.4,name=iPhone 6" SDK=iphonesimulator9.2
+    - DESTINATION="OS=8.3,name=iPhone 5S" SDK=iphonesimulator9.2
+    - DESTINATION="OS=8.2,name=iPhone 5" SDK=iphonesimulator9.2
+    - DESTINATION="OS=8.1,name=iPhone 4s" SDK=iphonesimulator9.2
 before_install:
   - gem install cocoapods --no-rdoc --no-ri --no-document --quiet
   - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
   - git submodule update
 script:
   - set -o pipefail
-  - xcodebuild -version
-  - xcodebuild -showsdks
-  - xcodebuild -project examples/app/GOSSpritedAnimationView.xcodeproj -scheme GOSSpritedAnimationView -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty -c; 
+  - xcodebuild -workspace examples/app/GOSSpritedAnimationView.xcworkspace -scheme GOSSpritedAnimationView -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO build test | xcpretty -c;
diff --git a/README.md b/README.md
index bcd1daf..84349b1 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,29 @@
 single image composed of individual sprite frames is used, and animation simply consists of
 updating the layer `contentsRect`.
 
+## Installation
+
+### Requirements
+
+- Xcode 7.0 or higher.
+- iOS SDK version 7.0 or higher.
+
+### Installation with CocoaPods
+
+To add this component to your Xcode project using CocoaPods, add the following to your `Podfile`:
+
+~~~ bash
+pod 'GOSScrollViewDelegateMultiplexer'
+~~~
+
+Then, run the following command:
+
+~~~ bash
+$ pod install
+~~~
+
+- - -
+
 ## Requirements
 
 - Xcode 7.0 or higher
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index 73f05e2..0000000
--- a/examples/README.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# GOSSpritedAnimationView example app
-
-This app demonstrates how to create a sprited animation view using the
-GOSSpritedAnimationView.
-
-## Requirements
-
-Xcode 7.0 or higher.
-
-## Where is the code?
-
-The relevant xcode project may be found in the 'app' directory.
-
-## Code structure
-
-This example shows how one might use a sprited animation view. A tap gesture is added to
-the view. When tapped, the animation starts. The control toggles between two sprite images.
diff --git a/examples/app/GOSSpritedAnimationView.xcodeproj/project.pbxproj b/examples/app/GOSSpritedAnimationView.xcodeproj/project.pbxproj
index bea887e..64a7f1f 100644
--- a/examples/app/GOSSpritedAnimationView.xcodeproj/project.pbxproj
+++ b/examples/app/GOSSpritedAnimationView.xcodeproj/project.pbxproj
@@ -15,8 +15,8 @@
 		5D090DF91C99A2900061344A /* SpritedAnimationViewTypicalUseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D090DF81C99A2900061344A /* SpritedAnimationViewTypicalUseViewController.m */; };
 		5D090DFD1C99A2C10061344A /* GOSSpritedAnimationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D090DFC1C99A2C10061344A /* GOSSpritedAnimationView.m */; };
 		5D090E001C99A36B0061344A /* SpritedAnimationView.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5D090DFF1C99A36B0061344A /* SpritedAnimationView.xcassets */; };
-		5D090E051C99A4D70061344A /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5D090E031C99A4D70061344A /* Info.plist */; };
-		5D090E061C99A4D70061344A /* GOSSpritedAnimationViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D090E041C99A4D70061344A /* GOSSpritedAnimationViewTests.m */; };
+		5DBC8D961CE65066006D5BB8 /* GOSSpritedAnimationViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DBC8D931CE65066006D5BB8 /* GOSSpritedAnimationViewTests.m */; };
+		5DBC8D971CE65066006D5BB8 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5DBC8D951CE65066006D5BB8 /* Info.plist */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -38,14 +38,14 @@
 		5D090DDE1C99A1E70061344A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		5D090DE11C99A1E70061344A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		5D090DE31C99A1E70061344A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		5D090DE81C99A1E70061344A /* GOSSpritedAnimationViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GOSSpritedAnimationViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		5D090DE81C99A1E70061344A /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		5D090DF71C99A2900061344A /* SpritedAnimationViewTypicalUseViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SpritedAnimationViewTypicalUseViewController.h; path = ../../SpritedAnimationViewTypicalUseViewController.h; sourceTree = "<group>"; };
 		5D090DF81C99A2900061344A /* SpritedAnimationViewTypicalUseViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SpritedAnimationViewTypicalUseViewController.m; path = ../../SpritedAnimationViewTypicalUseViewController.m; sourceTree = "<group>"; };
 		5D090DFB1C99A2C10061344A /* GOSSpritedAnimationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GOSSpritedAnimationView.h; sourceTree = "<group>"; };
 		5D090DFC1C99A2C10061344A /* GOSSpritedAnimationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GOSSpritedAnimationView.m; sourceTree = "<group>"; };
 		5D090DFF1C99A36B0061344A /* SpritedAnimationView.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = SpritedAnimationView.xcassets; sourceTree = "<group>"; };
-		5D090E031C99A4D70061344A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		5D090E041C99A4D70061344A /* GOSSpritedAnimationViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GOSSpritedAnimationViewTests.m; sourceTree = "<group>"; };
+		5DBC8D931CE65066006D5BB8 /* GOSSpritedAnimationViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GOSSpritedAnimationViewTests.m; sourceTree = "<group>"; };
+		5DBC8D951CE65066006D5BB8 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -80,7 +80,7 @@
 			isa = PBXGroup;
 			children = (
 				5D090DCF1C99A1E70061344A /* GOSSpritedAnimationView.app */,
-				5D090DE81C99A1E70061344A /* GOSSpritedAnimationViewTests.xctest */,
+				5D090DE81C99A1E70061344A /* UnitTests.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -132,21 +132,29 @@
 		5D090E011C99A4D70061344A /* tests */ = {
 			isa = PBXGroup;
 			children = (
-				5D090E021C99A4D70061344A /* unit */,
+				5DBC8D921CE65066006D5BB8 /* unit */,
 			);
 			name = tests;
 			path = ../../tests;
 			sourceTree = "<group>";
 		};
-		5D090E021C99A4D70061344A /* unit */ = {
+		5DBC8D921CE65066006D5BB8 /* unit */ = {
 			isa = PBXGroup;
 			children = (
-				5D090E031C99A4D70061344A /* Info.plist */,
-				5D090E041C99A4D70061344A /* GOSSpritedAnimationViewTests.m */,
+				5DBC8D931CE65066006D5BB8 /* GOSSpritedAnimationViewTests.m */,
+				5DBC8D941CE65066006D5BB8 /* resources */,
 			);
 			path = unit;
 			sourceTree = "<group>";
 		};
+		5DBC8D941CE65066006D5BB8 /* resources */ = {
+			isa = PBXGroup;
+			children = (
+				5DBC8D951CE65066006D5BB8 /* Info.plist */,
+			);
+			path = resources;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -167,9 +175,9 @@
 			productReference = 5D090DCF1C99A1E70061344A /* GOSSpritedAnimationView.app */;
 			productType = "com.apple.product-type.application";
 		};
-		5D090DE71C99A1E70061344A /* GOSSpritedAnimationViewTests */ = {
+		5D090DE71C99A1E70061344A /* UnitTests */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 5D090DF41C99A1E70061344A /* Build configuration list for PBXNativeTarget "GOSSpritedAnimationViewTests" */;
+			buildConfigurationList = 5D090DF41C99A1E70061344A /* Build configuration list for PBXNativeTarget "UnitTests" */;
 			buildPhases = (
 				5D090DE41C99A1E70061344A /* Sources */,
 				5D090DE51C99A1E70061344A /* Frameworks */,
@@ -180,9 +188,9 @@
 			dependencies = (
 				5D090DEA1C99A1E70061344A /* PBXTargetDependency */,
 			);
-			name = GOSSpritedAnimationViewTests;
+			name = UnitTests;
 			productName = GOSSpritedAnimationViewTests;
-			productReference = 5D090DE81C99A1E70061344A /* GOSSpritedAnimationViewTests.xctest */;
+			productReference = 5D090DE81C99A1E70061344A /* UnitTests.xctest */;
 			productType = "com.apple.product-type.bundle.unit-test";
 		};
 /* End PBXNativeTarget section */
@@ -217,7 +225,7 @@
 			projectRoot = "";
 			targets = (
 				5D090DCE1C99A1E70061344A /* GOSSpritedAnimationView */,
-				5D090DE71C99A1E70061344A /* GOSSpritedAnimationViewTests */,
+				5D090DE71C99A1E70061344A /* UnitTests */,
 			);
 		};
 /* End PBXProject section */
@@ -238,7 +246,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				5D090E051C99A4D70061344A /* Info.plist in Resources */,
+				5DBC8D971CE65066006D5BB8 /* Info.plist in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -260,7 +268,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				5D090E061C99A4D70061344A /* GOSSpritedAnimationViewTests.m in Sources */,
+				5DBC8D961CE65066006D5BB8 /* GOSSpritedAnimationViewTests.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -402,9 +410,9 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
-				INFOPLIST_FILE = ../../tests/unit/Info.plist;
+				INFOPLIST_FILE = ../../tests/unit/resources/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = com.google.GOSSpritedAnimationViewTests;
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.UnitTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GOSSpritedAnimationView.app/GOSSpritedAnimationView";
 			};
@@ -414,9 +422,9 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
-				INFOPLIST_FILE = ../../tests/unit/Info.plist;
+				INFOPLIST_FILE = ../../tests/unit/resources/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = com.google.GOSSpritedAnimationViewTests;
+				PRODUCT_BUNDLE_IDENTIFIER = com.google.UnitTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GOSSpritedAnimationView.app/GOSSpritedAnimationView";
 			};
@@ -443,7 +451,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		5D090DF41C99A1E70061344A /* Build configuration list for PBXNativeTarget "GOSSpritedAnimationViewTests" */ = {
+		5D090DF41C99A1E70061344A /* Build configuration list for PBXNativeTarget "UnitTests" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				5D090DF51C99A1E70061344A /* Debug */,
diff --git a/src/GOSSpritedAnimationView.h b/src/GOSSpritedAnimationView.h
index b5e7676..dd81c8a 100644
--- a/src/GOSSpritedAnimationView.h
+++ b/src/GOSSpritedAnimationView.h
@@ -17,72 +17,70 @@
 #import <UIKit/UIKit.h>
 
 /**
- * Animation view for loading in sprites.
- *
- * This control provides an alternative to animating an array of images with a UIImageView. Only
- * a single image composed of individual sprite frames is used, and animation simply consists of
- * updating the layer contentsRect.
- *
- * @ingroup GOSSpritedAnimationView
+ Animation view for loading in sprites.
+
+ This control provides an alternative to animating an array of images with a UIImageView. Only
+ a single image composed of individual sprite frames is used, and animation simply consists of
+ updating the layer contentsRect.
  */
 @interface GOSSpritedAnimationView : UIView
 
 /**
- * Optional tint color of the icon.
- *
- * If set to non-nil, the sprite sheet will be treated as an alpha mask and the color will be
- * applied.
+ Optional tint color of the icon.
+
+ If set to non-nil, the sprite sheet will be treated as an alpha mask and the color will be
+ applied.
  */
 @property(nonatomic, strong, nullable) UIColor *tintColor;
 
 /**
- * An image composed of a single column of individual sprite frames.
- *
- * Each sprite frame is assumed to be square.
+ An image composed of a single column of individual sprite frames.
+
+ Each sprite frame is assumed to be square.
  */
 @property(nonatomic, strong, nullable) UIImage *spriteSheetImage;
 
 /**
- * Framerate of the sprite playback in number of frames per second.
- *
- * Default is 60 frames per second.
+ Framerate of the sprite playback in number of frames per second.
+
+ Default is 60 frames per second.
  */
 @property(nonatomic, assign) NSInteger frameRate;
 
 /**
- * Number of times to repeat the animation.
- *
- * Setting to 0 means infinite. Default is 1.
+ Number of times to repeat the animation.
+
+ Setting to 0 means infinite. Default is 1.
  */
 @property(nonatomic, assign) NSInteger animationRepeatCount;
 
 /**
- * Returns whether the animation is playing.
- *
- * @return YES if the the sprite animation is playing.
+ Returns whether the animation is playing.
+
+ @return YES if the the sprite animation is playing.
  */
 @property(nonatomic, readonly, getter=isAnimating) BOOL animating;
 
 /**
- * Creates an animated sprite view.
- *
- * Designated initializer.
- *
- * @param spriteSheetImage A vertical sprite sheet of square images.
- * @return Initialized sprited animation view.
+ Creates an animated sprite view.
+
+ Designated initializer.
+
+ @param spriteSheetImage A vertical sprite sheet of square images.
+ @return Initialized sprited animation view.
  */
 - (nonnull instancetype)initWithSpriteSheetImage:
-    (nullable UIImage *)spriteSheetImage NS_DESIGNATED_INITIALIZER;
+        (nullable UIImage *)spriteSheetImage NS_DESIGNATED_INITIALIZER;
 
 /** Please use initWithSpriteSheetImage:. */
 - (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder NS_UNAVAILABLE;
 
 /**
- * Start the animation.
- *
- * Does nothing if the animation is already playing.
- *
- * @param completion Block called when transition completes.
+ Start the animation.
+
+ Does nothing if the animation is already playing.
+
+ @param completion Block called when transition completes.
  */
 - (void)startAnimatingWithCompletion:(nullable void (^)())completion;
 
diff --git a/src/GOSSpritedAnimationView.m b/src/GOSSpritedAnimationView.m
index 2caa8b9..a8377e5 100644
--- a/src/GOSSpritedAnimationView.m
+++ b/src/GOSSpritedAnimationView.m
@@ -18,8 +18,8 @@
 
 #import <QuartzCore/QuartzCore.h>
 
-static NSString *const kGOSSpriteAnimationKey = @"spriteAnimate";
-static const NSInteger kGOSSpriteFrameRateDefault = 60;
+static NSString *const kSpriteAnimationKey = @"spriteAnimate";
+static const NSInteger kSpriteFrameRateDefault = 60;
 
 @interface GOSSpritedAnimationView ()
 @property(nonatomic, assign) NSInteger numberOfFrames;
@@ -53,7 +53,7 @@
     _spriteLayer.bounds = self.layer.bounds;
     [self.layer addSublayer:_spriteLayer];
 
-    _frameRate = kGOSSpriteFrameRateDefault;
+    _frameRate = kSpriteFrameRateDefault;
     _singleFrameWidthInPercent = 1;
     _animationRepeatCount = 1;
     [self setSpriteSheetImage:spriteSheetImage];
@@ -94,13 +94,13 @@
     animation.removedOnCompletion = NO;
   }
 
-  [self.spriteLayer addAnimation:animation forKey:kGOSSpriteAnimationKey];
+  [self.spriteLayer addAnimation:animation forKey:kSpriteAnimationKey];
   [CATransaction commit];
 }
 
 - (void)stop {
   // Removing the animation will cause the completion block to be also called.
-  [self.spriteLayer removeAnimationForKey:kGOSSpriteAnimationKey];
+  [self.spriteLayer removeAnimationForKey:kSpriteAnimationKey];
 }
 
 - (void)seekToBeginning {
@@ -115,7 +115,7 @@
 }
 
 - (BOOL)isAnimating {
-  return ([self.spriteLayer animationForKey:kGOSSpriteAnimationKey] != nil);
+  return ([self.spriteLayer animationForKey:kSpriteAnimationKey] != nil);
 }
 
 #pragma mark - Mask Color Handling
diff --git a/tests/unit/Info.plist b/tests/unit/resources/Info.plist
similarity index 100%
rename from tests/unit/Info.plist
rename to tests/unit/resources/Info.plist