[
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control\n#\n# Pods/\n\n.DS_Store\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014, Bartosz Ciechanowski\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the {organization} nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "Revolved\n========\n\nThis is the complete source code of [Revolved](http://revolvedapp.com) – the 3D modelling app for the iPad that I've developed last summer. \n\n![Revolved](https://raw.githubusercontent.com/Ciechan/Revolved/master/screenshot.jpg)\n\n## Why?\n\nThere were many reasons for making Revolved open-sourced – [some internal](https://twitter.com/BCiechanowski/status/488649036250238977), [some external](https://twitter.com/BCiechanowski/status/487272741171908608), but it nonetheless feels like the perfect time to share the source code with the rest of the world. I strongly believe in giving back, as I've personally learned so much [from others](https://github.com/lemnar/Molecules).\n\nRevolved is *no longer under development*, but I'd be more than happy if its source helped making your app better.\n\n## Features\n\n- OpenGL ES 2.0 based rendering integrated with UIKit\n- custom animation engine\n- a bit of private API hackery\n\nThe line drawing system has been [explained in details on my blog](http://ciechanowski.me/blog/2014/02/18/drawing-bezier-curves/).\n\n## License\n\nRevolved source code is released under the [BSD 3-Clause License](https://github.com/Ciechan/Revolved/blob/master/LICENSE). You're free to use/copy/rewrite whatever pieces of code you desire. However, this license **does not cover the image assets** – you can't reuse them in your app. While I don't care that much for the PNGs, this is intended to prevent blatant resubmission of Revolved to the AppStore without a slightest alteration.\n\n\n## Contact\n\n[Bartosz Ciechanowski](http://ciechanowski.me)\n\n[@BCiechanowski](https://twitter.com/BCiechanowski)"
  },
  {
    "path": "Revolved/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@class RVRootViewController;\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n@property (strong, nonatomic) RVRootViewController *viewController;\n\n@end\n"
  },
  {
    "path": "Revolved/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n\n#import \"UIColor+RevolvedColors.h\"\n\n#import \"RVModelViewController.h\"\n#import \"RVRootViewController.h\"\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];\n    \n    self.viewController = [[RVRootViewController alloc] init];\n    self.window.rootViewController = self.viewController;\n    self.window.backgroundColor = [UIColor rv_backgroundColor];\n    self.window.tintColor = [UIColor rv_tintColor];\n    [self.window makeKeyAndVisible];\n    \n    NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];\n    \n    if (url != nil && [url isFileURL]) {\n        [self.viewController handleOpeningURL:url];\n    }\n    \n    return YES;\n}\n\n- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation\n{\n    if (url != nil && [url isFileURL]) {\n        [self.viewController handleOpeningURL:url];\n    }\n    \n    return YES;\n}\n\n- (void)applicationWillResignActive:(UIApplication *)application\n{\n    [[NSUserDefaults standardUserDefaults] synchronize];\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/AxisVertex.h",
    "content": "//\n//  AxisVertex.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#ifndef Revolved_AxisVertex_h\n#define Revolved_AxisVertex_h\n\ntypedef struct AxisVertex {\n    GLKVector3 p;\n    GLKVector4 color;\n} AxisVertex;\n\n#endif\n"
  },
  {
    "path": "Revolved/BCShader.h",
    "content": "//\n//  BCShader.h\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\ntypedef enum {\n    VertexAttribPosition,\n    VertexAttribNormal,\n    VertexAttribColor,\n    VertexAttribTexCoord,\n    VertexAttribAlpha,\n} VertexAttrib;\n\n#import <Foundation/Foundation.h>\n\n@interface BCShader : NSObject\n@property (nonatomic, readonly) GLuint program;\n\n- (BOOL)loadProgram;\n\n@end\n"
  },
  {
    "path": "Revolved/BCShader.m",
    "content": "//\n//  BCShader.m\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"BCShader.h\"\n\n@implementation BCShader\n\n\n#pragma mark - OpenGL ES 2 shader compilation\n\n- (BOOL)loadProgram\n{\n    GLuint vertShader, fragShader;\n    NSString *vertShaderPathname, *fragShaderPathname;\n    \n    _program = glCreateProgram();\n    \n    vertShaderPathname = [[NSBundle mainBundle] pathForResource:[self shaderName] ofType:@\"vsh\"];\n    if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {\n        NSLog(@\"Failed to compile vertex shader - %@\", [self shaderName]);\n        return NO;\n    }\n    \n    fragShaderPathname = [[NSBundle mainBundle] pathForResource:[self shaderName] ofType:@\"fsh\"];\n    if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {\n        NSLog(@\"Failed to compile fragment shader - %@\", [self shaderName]);\n        return NO;\n    }\n    \n    glAttachShader(_program, vertShader);\n    glAttachShader(_program, fragShader);\n    \n    [self bindAttributeLocations];\n    \n    if (![self linkProgram:_program]) {\n        NSLog(@\"Failed to link program %d for shader %@\", _program, [self shaderName]);\n        \n        if (vertShader) {\n            glDeleteShader(vertShader);\n            vertShader = 0;\n        }\n        if (fragShader) {\n            glDeleteShader(fragShader);\n            fragShader = 0;\n        }\n        if (_program) {\n            glDeleteProgram(_program);\n            _program = 0;\n        }\n        \n        return NO;\n    }\n    \n    [self getUniformLocations];\n    \n    if (vertShader) {\n        glDetachShader(_program, vertShader);\n        glDeleteShader(vertShader);\n    }\n    \n    if (fragShader) {\n        glDetachShader(_program, fragShader);\n        glDeleteShader(fragShader);\n    }\n    \n    return YES;\n}\n\n- (void)dealloc\n{\n    if (_program) {\n        glDeleteProgram(_program);\n        _program = 0;\n    }\n}\n\n- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file\n{\n    GLint status;\n    const GLchar *source;\n    \n    source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];\n    if (!source) {\n        NSLog(@\"Failed to load vertex shader\");\n        return NO;\n    }\n    \n    *shader = glCreateShader(type);\n    glShaderSource(*shader, 1, &source, NULL);\n    glCompileShader(*shader);\n    \n#if defined(DEBUG)\n    GLint logLength;\n    glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);\n    if (logLength > 0) {\n        GLchar *log = (GLchar *)malloc(logLength);\n        glGetShaderInfoLog(*shader, logLength, &logLength, log);\n        NSLog(@\"Shader compile log:\\n%s\", log);\n        free(log);\n    }\n#endif\n    \n    glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);\n    if (status == 0) {\n        glDeleteShader(*shader);\n        return NO;\n    }\n    \n    return YES;\n}\n\n- (BOOL)linkProgram:(GLuint)prog\n{\n    GLint status;\n    glLinkProgram(prog);\n    \n#if defined(DEBUG)\n    GLint logLength;\n    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);\n    if (logLength > 0) {\n        GLchar *log = (GLchar *)malloc(logLength);\n        glGetProgramInfoLog(prog, logLength, &logLength, log);\n        NSLog(@\"Program link log:\\n%s\", log);\n        free(log);\n    }\n#endif\n    \n    glGetProgramiv(prog, GL_LINK_STATUS, &status);\n    if (status == 0) {\n        return NO;\n    }\n    \n    return YES;\n}\n\n- (BOOL)validateProgram:(GLuint)prog\n{\n    GLint logLength, status;\n    \n    glValidateProgram(prog);\n    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);\n    if (logLength > 0) {\n        GLchar *log = (GLchar *)malloc(logLength);\n        glGetProgramInfoLog(prog, logLength, &logLength, log);\n        NSLog(@\"Program validate log:\\n%s\", log);\n        free(log);\n    }\n    \n    glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);\n    if (status == 0) {\n        return NO;\n    }\n    \n    return YES;\n}\n\n#pragma mark - Abstract\n\n- (void)bindAttributeLocations\n{\n    NSAssert(0, @\"Abstract method, implement in subclass\");\n}\n\n- (void)getUniformLocations\n{\n    NSAssert(0, @\"Abstract method, implement in subclass\");\n}\n\n- (NSString *)shaderName\n{\n    NSAssert(0, @\"Abstract method, implement in subclass\");\n    return nil;\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/BCShader_SubclassHooks.h",
    "content": "//\n//  BCShader_SubclassHooks.h\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n\n@interface BCShader ()\n\n- (void)bindAttributeLocations;\n- (void)getUniformLocations;\n- (NSString *)shaderName;\n\n@end\n"
  },
  {
    "path": "Revolved/Camera.h",
    "content": "//\n//  BCCamera.h\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <GLKit/GLKit.h>\n\n@interface Camera : NSObject\n\n//@property (nonatomic) GLKQuaternion rotation;\n@property (nonatomic) float distance;\n@property (nonatomic) float aspect;\n\n@property (nonatomic) GLKVector3 sceneTranslation;\n\n@property (nonatomic, readonly) GLKMatrix4 viewMatrix;\n@property (nonatomic, readonly) GLKMatrix4 viewProjectionMatrix;\n\n//@property (nonatomic, readonly) GLKMatrix4 rotationMatrix;\n@property (nonatomic, readonly) GLKMatrix4 projectionMatrix;\n\n- (void)updateMatrices;\n\n@end\n"
  },
  {
    "path": "Revolved/Camera.m",
    "content": "//\n//  Camera.m\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"Camera.h\"\n\n@implementation Camera\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _distance = 2.0;\n        _aspect = 1.0;\n    }\n    return self;\n}\n\n\n- (void)updateMatrices\n{\n    GLKMatrix4 distanceTranslation = GLKMatrix4MakeTranslation(0, 0, -_distance);\n    GLKMatrix4 sceneTranslation = GLKMatrix4MakeTranslation(_sceneTranslation.x, _sceneTranslation.y, _sceneTranslation.z);\n    \n    _viewMatrix = GLKMatrix4Multiply(sceneTranslation, distanceTranslation);\n  \n    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(M_PI/7.0, _aspect, 11.15, 18.05);\n    _projectionMatrix = projectionMatrix;\n    \n    _viewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, _viewMatrix);\n}\n\n@end\n"
  },
  {
    "path": "Revolved/CameraController.h",
    "content": "//\n//  CameraController.h\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@class Camera;\n\n@interface CameraController : NSObject\n\n@property (nonatomic) CGSize renderSurfaceSize;\n@property (nonatomic, readonly) GLKQuaternion quaternion;\n\n@property (nonatomic, strong, readonly) UIPanGestureRecognizer *panRecognizer;\n@property (nonatomic, strong, readonly) UIRotationGestureRecognizer *rotationRecognizer;\n\n- (void)resetPosition;\n- (void)stop;\n\n- (void)displayTick;\n- (void)animateToStartPositionWithDuration:(NSTimeInterval)duration;\n\n\n@end\n"
  },
  {
    "path": "Revolved/CameraController.m",
    "content": "//\n//  CameraController.m\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"CameraController.h\"\n#import \"Camera.h\"\n\n#import \"RVQuaternionAnimation.h\"\n#import \"RVAnimator.h\"\n\nstatic const float DeaccelerationFactor = 0.96;\n\nstatic const float ThresholdScreenPanVelocity = 100.0f;\nstatic const float ThresholdScreenRotationVelocity = 1.0f;\n\nstatic const float RotationVelocityToAngularScale = 0.01f;\nstatic const float PanVelocityToAngularScale = 0.00007f;\n\n\nstatic const GLKQuaternion IdentityQuaternion = {0.0f, 0.0f, 0.0f, 1.0f};\n\ntypedef NS_ENUM(NSInteger, CameraControllerState) {\n    CameraControllerStatePassive,\n    CameraControllerStatePanning,\n    CameraControllerStateRotating,\n    CameraControllerStateInertia\n};\n\n\n@interface CameraController() <UIGestureRecognizerDelegate>\n\n@property (nonatomic) CameraControllerState state;\n\n@property (nonatomic) GLKQuaternion startQuaternion;\n@property (nonatomic) GLKQuaternion panQuaternion;\n@property (nonatomic) GLKQuaternion rotationQuaternion;\n\n@property (nonatomic) GLKVector3 panStartPoint;\n@property (nonatomic) NSUInteger previousNumberOfPanTouches;\n\n@property (nonatomic) float currentRotation;\n@property (nonatomic) float previousRotation;\n\n@property (nonatomic) GLKVector3 inertiaAxis;\n@property (nonatomic) float inertiaVelocity;\n@property (nonatomic) float inertiaAngle;\n@property (nonatomic) float extraSlowdownFactor;\n\n\n@property (nonatomic) float panInertiaVelocity;\n@property (nonatomic) GLKVector3 panInertiaAxis;\n@property (nonatomic) float rotationInertiaVelocity;\n@property (nonatomic) GLKVector3 rotationInertiaAxis;\n\n@end\n\n@implementation CameraController\n\n\n- (id)init\n{\n    self = [super init];\n    if (self)\n    {\n        _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];\n        _panRecognizer.delegate = self;\n        _panRecognizer.cancelsTouchesInView = NO;\n        \n        _rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotate:)];\n        _rotationRecognizer.delegate = self;\n        _rotationRecognizer.cancelsTouchesInView = NO;\n        \n        [self resetPosition];\n        [self displayTick];\n    }\n    return self;\n}\n\n\n- (void)setState:(CameraControllerState)state\n{\n    if (state == _state) {\n        return;\n    }\n    \n    _state = state;\n    \n    if (state != CameraControllerStatePanning) {\n        [self resetPanQuaternion];\n    }\n    \n    if (state != CameraControllerStateRotating) {\n        [self resetRotationQuaternion];\n    }\n}\n\n\n- (void)resetPanQuaternion\n{\n    _startQuaternion = GLKQuaternionMultiply(_panQuaternion, _startQuaternion);\n    _panQuaternion = GLKQuaternionIdentity;\n}\n\n- (void)resetRotationQuaternion\n{\n    _startQuaternion = GLKQuaternionMultiply(_rotationQuaternion, _startQuaternion);\n    _rotationQuaternion = IdentityQuaternion;\n    _previousRotation = _currentRotation;\n}\n\n#pragma mark - Gesture Recognizers\n\n- (void)pan:(UIPanGestureRecognizer *)sender\n{\n    CGPoint viewPoint = [sender locationInView:sender.view];\n    CGPoint viewVelocity = [sender velocityInView:sender.view];\n    \n    switch (sender.state) {\n        case UIGestureRecognizerStateBegan:\n            [self beginPanAtPoint:[self pointToSphere:viewPoint]];\n            _previousNumberOfPanTouches = 1;\n            break;\n        case UIGestureRecognizerStateChanged:\n            [self continuePanAtPoint:[self pointToSphere:viewPoint] withNumberOfTouches:sender.numberOfTouches];\n            _previousNumberOfPanTouches = sender.numberOfTouches;\n            break;\n        case UIGestureRecognizerStateCancelled:\n        case UIGestureRecognizerStateEnded:\n            [self endPanWithVelocity:[self angularVelocityForScreenVelocty:viewVelocity atScreenPoint:viewPoint]];\n            break;\n        default:\n            break;\n    }\n    \n}\n\n- (void)rotate:(UIRotationGestureRecognizer *)sender\n{\n    CGFloat rotation = sender.rotation;\n    CGFloat velocity = sender.velocity;\n    \n    switch (sender.state) {\n        case UIGestureRecognizerStateBegan:\n            [self beginRotation:rotation];\n            break;\n        case UIGestureRecognizerStateChanged:\n            [self continueRotation:rotation withNumberOfTouches:sender.numberOfTouches];\n            break;\n        case UIGestureRecognizerStateCancelled:\n        case UIGestureRecognizerStateEnded:\n            [self endRotation:rotation withVelocity:velocity];\n            break;\n        default:\n            break;\n    }\n}\n\n- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer\n{\n    return YES;\n}\n\n- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch\n{\n    return touch.view == gestureRecognizer.view;\n}\n\n\n#pragma mark - Pan\n\n- (void)beginPanAtPoint:(GLKVector3)point\n{\n    [self resetInertia];\n    \n    _panStartPoint = point;\n    _panQuaternion = IdentityQuaternion;\n    \n    if (_state != CameraControllerStateRotating) {\n        _state = CameraControllerStatePanning;\n    }\n}\n\n- (void)continuePanAtPoint:(GLKVector3)point withNumberOfTouches:(NSUInteger)numberOfTouches\n{\n    if (numberOfTouches > 1 && _previousNumberOfPanTouches == 1) {\n        [self resetRotationQuaternion];\n    }\n    \n    if (numberOfTouches > 1) {\n        return;\n    }\n\n    if (numberOfTouches == 1 && _previousNumberOfPanTouches > 1) {\n        self.panStartPoint = point;\n    }\n    \n    if (_state == CameraControllerStateRotating) {\n        self.state = CameraControllerStatePanning;\n        self.panStartPoint = point;\n    }\n    \n    GLKVector3 panEndPoint = point;\n    _panQuaternion = [self quaternionFromStartPoint:_panStartPoint toEndPoint:panEndPoint];\n}\n\n\n- (void)endPanWithVelocity:(GLKVector3)velocity\n{\n    float length = GLKVector3Length(velocity);\n    \n    _panInertiaAxis = GLKVector3MultiplyScalar(velocity, 1.0/length);\n    _panInertiaVelocity = length;\n    [self resolveInertia];\n}\n\n#pragma mark - Rotation\n\n- (void)beginRotation:(CGFloat)rotation\n{\n    [self resetInertia];\n    _previousRotation = 0.0f;\n    \n    if (_state == CameraControllerStatePassive) {\n        self.state = CameraControllerStateRotating;\n    }\n    \n}\n\n- (void)continueRotation:(CGFloat)rotation withNumberOfTouches:(NSUInteger)touches\n{\n    if (touches == 2) {\n        if (_state == CameraControllerStatePanning) {\n            self.state = CameraControllerStateRotating;\n        }\n        \n        _currentRotation = rotation;\n        _rotationQuaternion = GLKQuaternionMakeWithAngleAndAxis(rotation - _previousRotation, 0, 0, -1);\n    } else {\n        if (_state == CameraControllerStateRotating) {\n            self.state = CameraControllerStatePanning;\n        }\n    }\n}\n\n- (void)endRotation:(CGFloat)rotation withVelocity:(CGFloat)velocity\n{\n    float absVelocity = fabsf(velocity);\n    _rotationInertiaAxis = GLKVector3Make(0.0f, 0.0f, -1.0f);\n    _rotationInertiaVelocity = (absVelocity > ThresholdScreenRotationVelocity ? velocity : 0.0) * RotationVelocityToAngularScale;\n    [self resolveInertia];\n}\n\n- (void)resolveInertia\n{\n    if (_rotationInertiaVelocity != 0.0f) {\n        _inertiaAxis = _rotationInertiaAxis;\n        _inertiaVelocity = _rotationInertiaVelocity;\n    } else if (_panInertiaVelocity > 0.0f) {\n        _inertiaAxis = _panInertiaAxis;\n        _inertiaVelocity = _panInertiaVelocity;\n    }\n    \n    self.state = CameraControllerStatePassive;\n}\n\n\n- (void)displayTick\n{\n    _inertiaVelocity *= DeaccelerationFactor * _extraSlowdownFactor;\n    _inertiaAngle += _inertiaVelocity;\n    \n    GLKQuaternion intertiaQuaternion = GLKQuaternionMakeWithAngleAndVector3Axis(_inertiaAngle, _inertiaAxis);\n    GLKQuaternion q = GLKQuaternionMultiply(GLKQuaternionMultiply(intertiaQuaternion, _rotationQuaternion),\n                                            GLKQuaternionMultiply(_panQuaternion, _startQuaternion));\n    _quaternion = q;\n}\n\n\n- (void)resetInertia\n{\n    GLKQuaternion intertiaQuaternion = GLKQuaternionMakeWithAngleAndVector3Axis(_inertiaAngle, _inertiaAxis);\n    _startQuaternion = GLKQuaternionMultiply(intertiaQuaternion, _startQuaternion);\n    \n    _inertiaAxis = GLKVector3Make(1.0f, 0.0f, 0.0f);\n    _inertiaAngle = 0.0f;\n    _inertiaVelocity = 0.0f;\n    _extraSlowdownFactor = 1.0f;\n\n    _panInertiaVelocity = 0.0f;\n    _rotationInertiaVelocity = 0.0f;\n    \n    if (_state == CameraControllerStateInertia) {\n        self.state = CameraControllerStatePassive;\n    }\n}\n\n- (void)stop\n{\n    _extraSlowdownFactor = 0.65;\n}\n\n- (void)resetPosition\n{\n    _startQuaternion = BaseQuaternion;\n    _panQuaternion = GLKQuaternionIdentity;\n    _rotationQuaternion = GLKQuaternionIdentity;;\n    _inertiaAngle = 0.0f;\n    \n    [self resetInertia];\n    [self displayTick];\n}\n\n\n- (GLKQuaternion)quaternionFromStartPoint:(GLKVector3)start toEndPoint:(GLKVector3)end\n{\n    const float epsilon = 0.00001;\n    \n    GLKVector3 cross = GLKVector3CrossProduct(start, end);\n    float length = GLKVector3Length(cross);\n    \n    if (length < epsilon) {\n        return GLKQuaternionIdentity;\n    } else {\n        GLKVector3 axis = GLKVector3MultiplyScalar(cross, 1.0/length);\n        float angle = 2.0 * acosf(GLKVector3DotProduct(start, end));\n        \n        return GLKQuaternionMakeWithAngleAndVector3Axis(angle, axis);\n    }\n}\n\n\n#pragma mark - Trackball\n\n- (GLKVector3)normalizedScreenVectorFromPoint:(CGPoint)point\n{\n    CGSize surfaceSize = self.renderSurfaceSize;\n    GLKVector3 vector = GLKVector3Make(point.x - surfaceSize.width/2.0, surfaceSize.height/2.0 - point.y, 0.0f);\n    \n    return GLKVector3MultiplyScalar(vector, 2.0f/(MAX(surfaceSize.width, surfaceSize.height)));\n}\n\n- (GLKVector3)pointToSphere:(CGPoint)pointOnScreen\n{\n    GLKVector3 point = [self normalizedScreenVectorFromPoint:pointOnScreen];\n    \n    CGFloat length = point.x*point.x + point.y*point.y;\n    CGFloat radius = 1.0f;\n    \n    if (length > radius * radius / 2.0f) {\n        point.z = (radius * radius / 2.0) / sqrtf(length);\n    } else {\n        point.z = sqrtf(radius * radius - length);\n    }\n    \n    return GLKVector3Normalize(point);\n    \n}\n\n- (GLKVector3)angularVelocityForScreenVelocty:(CGPoint)screenVelocity atScreenPoint:(CGPoint)screenPoint\n{\n    CGFloat length = sqrtf(screenVelocity.x * screenVelocity.x + screenVelocity.y * screenVelocity.y);\n    \n    if (length < ThresholdScreenPanVelocity) {\n        return GLKVector3Make(0.0f, 0.0f, 0.0f);\n    }\n    \n    CGPoint endPoint = CGPointMake(screenPoint.x + screenVelocity.x/length, screenPoint.y + screenVelocity.y/length);\n    \n    GLKVector3 start = [self pointToSphere:screenPoint];\n    GLKVector3 end = [self pointToSphere:endPoint];\n    \n    GLKVector3 axis = GLKVector3Normalize(GLKVector3CrossProduct(start, end));\n    \n    return GLKVector3MultiplyScalar(axis, length * PanVelocityToAngularScale);\n}\n\n#pragma mark - Animation\n\n\n- (void)animateToStartPositionWithDuration:(NSTimeInterval)duration\n{\n    self.state = CameraControllerStatePassive;\n    [self resetInertia];\n    \n    RVQuaternionAnimation *animation = [RVQuaternionAnimation quaternionAnimationFromValue:self.startQuaternion toValue:BaseQuaternion withDuration:duration];\n    [[RVAnimator sharedAnimator] addAnimation:animation forKey:@\"startQuaternion\" toTarget:self];\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/Color.h",
    "content": "//\n//  Color.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#ifndef Revolved_Color_h\n#define Revolved_Color_h\n\ntypedef struct Color {\n    unsigned char r, g, b;\n} Color;\n\nstatic inline GLKVector3 colorToGLKVector3(Color color)\n{\n    return GLKVector3Make(color.r / 255.0, color.g / 255.0, color.b / 255.0);\n}\n\nstatic inline Color colorWithRGB(char red, char green, char blue)\n{\n    return (Color){red, green, blue};\n}\n\nstatic inline Color colorWithHexColor(NSUInteger hexColor)\n{\n    return colorWithRGB((hexColor & 0xFF0000) >> 16,\n                        (hexColor & 0x00FF00) >> 8,\n                        (hexColor & 0x0000FF) >> 0);\n}\n\n\n\n#endif\n"
  },
  {
    "path": "Revolved/Constants.h",
    "content": "//\n//  Constants.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 05.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#ifndef Revolved_Constants_h\n#define Revolved_Constants_h\n\nstatic const NSUInteger Spans = 14;\nstatic const NSUInteger StripesPerSpan = 4;\n\nstatic const NSUInteger SegmentLimit = 60;\n\n#endif\n"
  },
  {
    "path": "Revolved/DrawGestureRecognizer.h",
    "content": "//\n//  DrawGestureRecognizer.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface DrawGestureRecognizer : UIPanGestureRecognizer\n\n- (CGPoint)firstTouchLocationInView:(UIView *)view;\n\n@end\n"
  },
  {
    "path": "Revolved/DrawGestureRecognizer.m",
    "content": "//\n//  DrawGestureRecognizer.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIGestureRecognizerSubclass.h>\n#import \"DrawGestureRecognizer.h\"\n\n@interface DrawGestureRecognizer()\n\n@property (nonatomic, strong) UITouch *firstTouch;\n@property (nonatomic) CGPoint firstTouchLocation;\n\n@end\n\n@implementation DrawGestureRecognizer\n\n\n\n- (CGPoint)firstTouchLocationInView:(UIView *)view\n{\n    return [self.view convertPoint:self.firstTouchLocation toView:view];\n}\n\n\n- (void)reset\n{\n    [super reset];\n    self.firstTouch = nil;\n}\n\n- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event\n{\n    if (self.numberOfTouches > 0) {\n        return;\n    }\n    \n    if (touches.count > 1) {\n        touches = [NSSet setWithObject:[touches anyObject]];\n    }\n    \n    [super touchesBegan:touches withEvent:event];\n\n    self.firstTouch = [touches anyObject];\n    self.firstTouchLocation = [self.firstTouch locationInView:self.view];\n}\n\n- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event\n{\n    if (![touches containsObject:self.firstTouch]) {\n        return;\n    }\n    \n    touches = [NSSet setWithObject:self.firstTouch];\n    \n    [super touchesMoved:touches withEvent:event];\n}\n\n- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event\n{\n    if (![touches containsObject:self.firstTouch]) {\n        return;\n    }\n    \n    touches = [NSSet setWithObject:self.firstTouch];\n    \n    [super touchesEnded:touches withEvent:event];\n}\n\n- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event\n{\n    if (![touches containsObject:self.firstTouch]) {\n        return;\n    }\n    \n    touches = [NSSet setWithObject:self.firstTouch];\n    \n    [super touchesCancelled:touches withEvent:event];\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/Geometry.h",
    "content": "//\n//  Geometry.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#ifndef Revolved_Geometry_h\n#define Revolved_Geometry_h\n\n\nstatic inline float GLKVector2DistanceSq(GLKVector2 vectorStart, GLKVector2 vectorEnd)\n{\n    GLKVector2 diff = GLKVector2Subtract(vectorEnd, vectorStart);\n    return GLKVector2DotProduct(diff, diff);\n}\n\n\n\nstatic inline float SquareDistancePointSegment(GLKVector2 a, GLKVector2 b, GLKVector2 c)\n{\n    GLKVector2 ab = GLKVector2Subtract(b, a);\n    GLKVector2 ac = GLKVector2Subtract(c, a);\n    \n    float e = GLKVector2DotProduct(ac, ab);\n    if (e <= 0.0f) {\n        return GLKVector2DotProduct(ac, ac);\n    }\n\n    GLKVector2 bc = GLKVector2Subtract(c, b);\n    \n    float f = GLKVector2DotProduct(ab, ab);\n    if (e >= f) {\n        return GLKVector2DotProduct(bc, bc);\n    }\n    \n    return GLKVector2DotProduct(ac, ac) - e * e / f;\n}\n\n\n// given segment ab and point c, computes closest point d on ab\n// returns UNCLAMPPED value of t\nstatic inline GLKVector2 ClosestPointOnSegmentForPoint(GLKVector2 a, GLKVector2 b, GLKVector2 c, float *t)\n{\n    GLKVector2 ab = GLKVector2Subtract(b, a);\n    GLKVector2 ac = GLKVector2Subtract(c, a);\n    \n    float realT = GLKVector2DotProduct(ac, ab) / GLKVector2DotProduct(ab, ab);\n    *t = realT;\n    \n    return GLKVector2Add(a, GLKVector2MultiplyScalar(ab, realT));\n}\n\n#endif\n"
  },
  {
    "path": "Revolved/Images.xcassets/AddFull.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"AddFull.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"AddFull@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/AddPlus.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"AddPlus.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"AddPlus@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/AddSemiCircle.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"AddSemiCircle.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"AddSemiCircle@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"50x50\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"50x50\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"72x72\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"72x72\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon@2x.png\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/BackButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"BackButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"BackButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Camera.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Camera.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Camera@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/CloneButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"CloneButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"CloneButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/ConfirmButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"ConfirmButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"ConfirmButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/CreditsButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"CreditsButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"CreditsButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/CreditsText.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"CreditsText.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"CreditsText@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/DeclineButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"DeclineButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"DeclineButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Dots.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Dots.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Dots@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/DotsSelected.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"DotsSelected.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"DotsSelected@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Empty.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Empty.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Empty@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Facebook.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Facebook.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Facebook@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Gear.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Gear.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Gear@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/LaunchImage.launchimage/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"filename\" : \"Default.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"7.0\",\n      \"filename\" : \"Default@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"orientation\" : \"portrait\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"ipad\",\n      \"extent\" : \"to-status-bar\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Logo.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Logo.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Logo@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/MailButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"MailButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"MailButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/ObjFileIcon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"ObjFileIcon.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"ObjFileIcon@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/RateButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"RateButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"RateButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/ReviewBegger.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"ReviewBegger.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"ReviewBegger@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/RvlvdFileIcon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"RvlvdFileIcon.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"RvlvdFileIcon@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Save.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Save.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Save@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/SegmentLimit.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"SegmentLimit.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"SegmentLimit@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/ShareButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"ShareButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"ShareButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Stem.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Stem.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Stem@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/StlFileIcon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"StlFileIcon.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"StlFileIcon@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TrashButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TrashButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"TrashButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TrashCan.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TrashCan.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"TrashCan@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TrashLid.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TrashLid.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"TrashLid@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialAxis.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialAxis.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialAxis3D.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialAxis3D.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"TutorialButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialCloseButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialCloseButtong.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"TutorialCloseButtong@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialControlPoint.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialControlPoint.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialEndPoint.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialEndPoint.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialFinishButton.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialFinishButton.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"TutorialFinishButton@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialGetToKnow.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialGetToKnow.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"TutorialGetToKnow@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialHaveFun.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialHaveFun.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"TutorialHaveFun@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialLine.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialLine.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialLineBend1.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialLineBend1.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialLineBend3.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialLineBend3.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialLineBend5.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialLineBend5.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialLineBend7.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialLineBend7.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialLineBend9.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialLineBend9.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialLineLong.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialLineLong.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialRevolvedBack.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialRevolvedBack.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialRevolvedFront.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialRevolvedFront.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialSegment1.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialSegment1.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialSegment2.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialSegment2.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialSegment3.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialSegment3.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialWheel.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialWheel.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialiPadCamera.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialiPadCamera.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialiPadHomeBlack.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialiPadHomeBlack.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/TutorialiPadHomeWhite.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"TutorialiPadHomeWhite.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/Images.xcassets/Twitter.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\",\n      \"filename\" : \"Twitter.png\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\",\n      \"filename\" : \"Twitter@2x.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Revolved/LineVertex.h",
    "content": "//\n//  LineVertex.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#ifndef Revolved_LineVertex_h\n#define Revolved_LineVertex_h\n\ntypedef struct LineVertex {\n    GLKVector2 p;\n    GLKVector3 color;\n} LineVertex;\n\n\n#endif\n"
  },
  {
    "path": "Revolved/MFMailComposeViewController+SendIfPossible.h",
    "content": "//\n//  MFMailComposeViewController+SendIfPossible.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 24.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <MessageUI/MessageUI.h>\n\n@interface MFMailComposeViewController (SendIfPossible)\n\n+ (BOOL)rv_canSendEmailIfNotShowAlert;\n+ (void)rv_showDefaultFailAlertWithError:(NSError *)error;\n\n@end\n"
  },
  {
    "path": "Revolved/MFMailComposeViewController+SendIfPossible.m",
    "content": "//\n//  MFMailComposeViewController+SendIfPossible.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 24.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"MFMailComposeViewController+SendIfPossible.h\"\n\n@implementation MFMailComposeViewController (SendIfPossible)\n\n+ (BOOL)rv_canSendEmailIfNotShowAlert\n{\n    if ([self canSendMail]) {\n        return YES;\n    }\n    \n    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@\"Error sending e-mail\"\n                                                    message:@\"Your iPad doesn't have an e-mail account setup\"\n                                                   delegate:nil\n                                          cancelButtonTitle:@\"OK\"\n                                          otherButtonTitles:nil];\n    [alert show];\n    \n    return NO;\n}\n\n+ (void)rv_showDefaultFailAlertWithError:(NSError *)error\n{\n    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@\"Error sending e-mail\"\n                                                    message:[error localizedDescription]\n                                                   delegate:nil\n                                          cancelButtonTitle:@\"OK\"\n                                          otherButtonTitles:nil];\n    [alert show];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/NSArray+Functional.h",
    "content": "//\n//  NSArray+Functional.h\n//  Ico\n//\n//  Created by Bartosz Ciechanowski on 21.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSArray (Functional)\n\n- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block;\n- (NSArray *)filterObjectsUsingBlock:(BOOL (^)(id obj, NSUInteger idx))block;\n\n@end\n"
  },
  {
    "path": "Revolved/NSArray+Functional.m",
    "content": "//\n//  NSArray+Functional.m\n//  Ico\n//\n//  Created by Bartosz Ciechanowski on 21.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"NSArray+Functional.h\"\n\n@implementation NSArray (Functional)\n\n- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block\n{\n    NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]];\n    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {\n        [result addObject:block(obj, idx)];\n    }];\n    return [result copy];\n}\n\n- (NSArray *)filterObjectsUsingBlock:(BOOL (^)(id obj, NSUInteger idx))block\n{\n    NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]];\n    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {\n        if (block(obj, idx)) {\n            [result addObject:obj];\n        }\n    }];\n    return [result copy];\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/NSError+RevolvedErrors.h",
    "content": "//\n//  NSError+RevolvedErrors.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSError (RevolvedErrors)\n\n+ (NSError *)malformedFileError;\n+ (NSError *)obsoleteAppVersionError;\n\n@end\n"
  },
  {
    "path": "Revolved/NSError+RevolvedErrors.m",
    "content": "//\n//  NSError+RevolvedErrors.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"NSError+RevolvedErrors.h\"\n\nstatic NSString * const ErrorDomain = @\"com.bartoszciechanowski.revolved\";\n\n@implementation NSError (RevolvedErrors)\n\n+ (NSError *)malformedFileError\n{\n    return [NSError errorWithDomain:ErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @\"The model you're trying to import seems to be malformed\"}];\n}\n\n+ (NSError *)obsoleteAppVersionError\n{\n    return [NSError errorWithDomain:ErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @\"You need to update Revolved in the AppStore to import this model\"}];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/NSMapTable+BlockEnumeration.h",
    "content": "//\n//  NSMapTable+BlockEnumeration.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSMapTable (BlockEnumeration)\n\n- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block;\n\n@end\n"
  },
  {
    "path": "Revolved/NSMapTable+BlockEnumeration.m",
    "content": "//\n//  NSMapTable+BlockEnumeration.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"NSMapTable+BlockEnumeration.h\"\n\n@implementation NSMapTable (BlockEnumeration)\n\n- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block\n{\n    BOOL stop = NO;\n    for (id key in self) {\n        block(key, [self objectForKey:key], &stop);\n        if (stop) {\n            return;\n        }\n    }\n}\n\n@end\n"
  },
  {
    "path": "Revolved/NSMutableArray+MoveObject.h",
    "content": "//\n//  NSMutableArray+MoveObject.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSMutableArray (MoveObject)\n\n- (void)moveObjectAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;\n\n@end\n"
  },
  {
    "path": "Revolved/NSMutableArray+MoveObject.m",
    "content": "//\n//  NSMutableArray+MoveObject.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"NSMutableArray+MoveObject.h\"\n\n@implementation NSMutableArray (MoveObject)\n\n- (void)moveObjectAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex\n{\n    id object = [self objectAtIndex:fromIndex];\n    [self removeObjectAtIndex:fromIndex];\n    [self insertObject:object atIndex:toIndex];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/NSMutableOrderedSet+MoveObject.h",
    "content": "//\n//  NSMutableOrderedSet+MoveObject.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSMutableOrderedSet (MoveObject)\n\n- (void)moveObjectAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;\n\n@end\n"
  },
  {
    "path": "Revolved/NSMutableOrderedSet+MoveObject.m",
    "content": "//\n//  NSMutableOrderedSet+MoveObject.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"NSMutableOrderedSet+MoveObject.h\"\n\n@implementation NSMutableOrderedSet (MoveObject)\n\n- (void)moveObjectAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex\n{\n    id object = [self objectAtIndex:fromIndex];\n    [self removeObjectAtIndex:fromIndex];\n    [self insertObject:object atIndex:toIndex];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/PointVertex.h",
    "content": "//\n//  PointVertex.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#ifndef Revolved_PointVertex_h\n#define Revolved_PointVertex_h\n\ntypedef struct PointVertex {\n    GLKVector2 p;\n    GLKVector2 uv;\n    float      alpha;\n} PointVertex;\n\n#endif\n"
  },
  {
    "path": "Revolved/RVAddProgressView.h",
    "content": "//\n//  RVAddProgressView.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVAddProgressView : UIView\n\n@property (nonatomic, strong, readonly) UIButton *plus;\n@property (nonatomic) float progress;\n\n- (void)setProgress:(float)progress allowingFull:(BOOL)allowFull;\n\n@end\n"
  },
  {
    "path": "Revolved/RVAddProgressView.m",
    "content": "//\n//  RVAddProgressView.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAddProgressView.h\"\n\n#import <QuartzCore/QuartzCore.h>\n\n@interface RVAddProgressView()\n\n@property (nonatomic, strong) UIView *firstContainer;\n@property (nonatomic, strong) UIView *secondContainer;\n\n@property (nonatomic, strong) UIImageView *firstSemiCircle;\n@property (nonatomic, strong) UIImageView *secondSemiCircle;\n\n@property (nonatomic, strong, readwrite) UIButton *plus;\n@property (nonatomic, strong) UIImageView *plusFull;\n\n\n@end\n\n@implementation RVAddProgressView\n\n- (id)initWithFrame:(CGRect)frame\n{\n    self = [super initWithFrame:frame];\n    if (self) {\n        [self commonInit];\n    }\n    return self;\n}\n\n- (id)initWithCoder:(NSCoder *)aDecoder\n{\n    self = [super initWithCoder:aDecoder];\n    if (self) {\n        [self commonInit];\n    }\n    return self;\n}\n\n- (void)commonInit\n{\n    self.backgroundColor = [UIColor clearColor];\n    \n    _firstContainer = [[UIView alloc] init];\n    _firstContainer.clipsToBounds = YES;\n    _firstContainer.backgroundColor = [UIColor clearColor];\n    _firstContainer.userInteractionEnabled = NO;\n    \n    _secondContainer = [[UIView alloc] init];\n    _secondContainer.clipsToBounds = YES;\n    _secondContainer.backgroundColor = [UIColor clearColor];\n    _secondContainer.userInteractionEnabled = NO;\n    \n    _firstSemiCircle = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@\"AddSemiCircle\"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];\n    _firstSemiCircle.layer.anchorPoint = CGPointMake(0.0f, 0.5f);\n    \n    _secondSemiCircle = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@\"AddSemiCircle\"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];\n    _secondSemiCircle.layer.anchorPoint = CGPointMake(0.0f, 0.5f);\n    \n    _plus = [UIButton buttonWithType:UIButtonTypeSystem];\n    _plus.bounds = CGRectMake(0, 0, 44.0f, 44.0f);\n    _plus.exclusiveTouch = YES;\n    [_plus setImage:[UIImage imageNamed:@\"AddPlus\"] forState:UIControlStateNormal];\n    \n    _plusFull = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@\"AddFull\"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];\n    _plusFull.alpha = 0.0f;\n    \n    [self addSubview:_firstContainer];\n    [self addSubview:_secondContainer];\n    [self addSubview:_plus];\n    [self addSubview:_plusFull];\n    \n    [_firstContainer addSubview:_firstSemiCircle];\n    [_secondContainer addSubview:_secondSemiCircle];\n    \n    [self setProgress:0.0f];\n}\n\n- (void)layoutSubviews\n{\n    [super layoutSubviews];\n    \n    CGRect bounds = self.bounds;\n    CGRect leftFrame, rightFrame;\n    CGRectDivide(bounds, &rightFrame, &leftFrame, bounds.size.width/2.0f, CGRectMaxXEdge);\n    \n    _firstContainer.frame = rightFrame;\n    _secondContainer.frame = leftFrame;\n    \n    _firstSemiCircle.center = CGPointMake(0.0, rightFrame.size.height/2.0);\n    _secondSemiCircle.center = CGPointMake(leftFrame.size.width, leftFrame.size.height/2.0);\n    \n    _plus.center = CGPointMake(bounds.size.width/2.0, bounds.size.height/2.0);\n    _plusFull.center = CGPointMake(bounds.size.width/2.0, bounds.size.height/2.0);\n}\n\n- (void)setProgress:(float)progress\n{\n    [self setProgress:progress allowingFull:NO];\n}\n\n- (void)setProgress:(float)progress allowingFull:(BOOL)allowFull\n{\n    progress = MIN(MAX(0.0f, progress), 1.0f);\n    \n    _firstSemiCircle.transform = CGAffineTransformMakeRotation(M_PI + 2.0f * M_PI * MIN(progress, 0.5f));\n    _secondSemiCircle.transform = CGAffineTransformMakeRotation(M_PI * 2.0f * MAX(progress - 0.5f, 0.0f));\n    \n    if (progress == 1.0f && _progress < 1.0f && allowFull) {\n        [UIView animateWithDuration:0.15 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{\n            _plus.alpha = 0.0f;\n            _firstContainer.alpha = 0.0f;\n            _secondContainer.alpha = 0.0f;\n            \n            _plusFull.alpha = 1.0f;\n        } completion:NULL];\n    } else if (_progress == 1.0f && progress < 1.0f) {\n        [UIView animateWithDuration:0.15 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{\n            _plus.alpha = 1.0f;\n            _firstContainer.alpha = 1.0f;\n            _secondContainer.alpha = 1.0f;\n            \n            _plusFull.alpha = 0.0f;\n        } completion:NULL];\n    }\n    \n    _progress = progress;\n}\n\n\n@end\n\n"
  },
  {
    "path": "Revolved/RVAnchorPoint.h",
    "content": "//\n//  RVAnchorPoint.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPoint.h\"\n\n@interface RVAnchorPoint : RVPoint\n\n@property (nonatomic) BOOL hasControlPoint;\n\n@end\n"
  },
  {
    "path": "Revolved/RVAnchorPoint.m",
    "content": "//\n//  RVAnchorPoint.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAnchorPoint.h\"\n\n@implementation RVAnchorPoint\n\n- (PointType)type\n{\n    return PointTypeAnchor;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVAnimation.h",
    "content": "//\n//  RVAnimation.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\ntypedef void (^CompletionBlock)(void);\n\ntypedef NS_ENUM(NSInteger, RVAnimationCurve) {\n    RVAnimationCurveEaseInOut,\n    RVAnimationCurveEaseIn,\n    RVAnimationCurveEaseOut,\n    RVAnimationCurveQuartEaseOut,\n    RVAnimationCurveQuinticEaseInOut,\n    RVAnimationCurveElasticEaseOut,\n    RVAnimationCurveJumpEaseIn,\n    RVAnimationCurveJumpEaseOut,\n    RVAnimationCurveJelly,\n    RVAnimationCurveLinear\n};\n\n\n\n@interface RVAnimation : NSObject\n\n@property (nonatomic) NSTimeInterval duration;\n@property (nonatomic) NSTimeInterval delay;\n@property (nonatomic) NSTimeInterval time; // don't touch unless you know what you're doing\n\n@property (nonatomic) RVAnimationCurve animationCurve;\n\n@property (nonatomic, copy) CompletionBlock completionBlock;\n\n@end\n"
  },
  {
    "path": "Revolved/RVAnimation.m",
    "content": "//\n//  RVAnimation.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAnimation.h\"\n#import \"RVAnimation_Private.h\"\n\n@implementation RVAnimation\n\n@end\n"
  },
  {
    "path": "Revolved/RVAnimation_Private.h",
    "content": "//\n//  RVAnimation_Private.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAnimation.h\"\n\n@class RVSprite;\n@interface RVAnimation ()\n\n@property (nonatomic, strong) NSString *key;\n@property (nonatomic, weak) id target;\n\n@end\n"
  },
  {
    "path": "Revolved/RVAnimator.h",
    "content": "//\n//  RVAnimator.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@class RVAnimation;\n@interface RVAnimator : NSObject\n\n+ (instancetype)sharedAnimator;\n\n- (void)addAnimation:(RVAnimation *)animation forKey:(NSString *)key toTarget:(id)target;\n- (RVAnimation *)animationforKey:(NSString *)key forTarget:(id)target;\n- (void)removeAnimationForKey:(NSString *)key fromTarget:(id)target;\n\n- (void)tick:(NSTimeInterval)dt;\n\n@end\n"
  },
  {
    "path": "Revolved/RVAnimator.m",
    "content": "//\n//  RVAnimator.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAnimator.h\"\n#import \"RVAnimation_Private.h\"\n\n#import \"RVAnimation.h\"\n#import \"RVFloatAnimation.h\"\n#import \"RVVectorAnimation.h\"\n#import \"RVQuaternionAnimation.h\"\n\n#import \"RVLineSprite.h\"\n#import \"RVPointSprite.h\"\n#import \"RVModelSprite.h\"\n\n#import \"UIView+RotationAnimation.h\"\n\ntypedef float (^Executor)(RVAnimation *animation, float p);\ntypedef float (*Curve)(float time);\n\nstatic NSDictionary *keyExecutorMap;\n\n\n@interface RVAnimator()\n\n@property (nonatomic, strong) NSMapTable *targetToAnimationsDictionaryMap;\n@property (nonatomic, strong) NSHashTable *allAnimations;\n\n@end\n\n@implementation RVAnimator\n\n+ (instancetype)sharedAnimator\n{\n    static RVAnimator *sharedInstance = nil;\n    static dispatch_once_t predicate;\n    dispatch_once(&predicate, ^{\n        sharedInstance = [[RVAnimator alloc] init];\n    });\n    \n    return sharedInstance;\n}\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        self.targetToAnimationsDictionaryMap = [NSMapTable weakToStrongObjectsMapTable];\n        self.allAnimations = [NSHashTable weakObjectsHashTable];\n    }\n    return self;\n}\n\n- (NSMutableDictionary *)animationDictionaryForTarget:(id)target\n{\n    NSMutableDictionary *dictionary = [self.targetToAnimationsDictionaryMap objectForKey:target];\n    \n    if (!dictionary) {\n        dictionary = [NSMutableDictionary dictionary];\n        [self.targetToAnimationsDictionaryMap setObject:dictionary forKey:target];\n    }\n    \n    return dictionary;\n}\n\n- (void)addAnimation:(RVAnimation *)animation forKey:(NSString *)key toTarget:(id)target\n{\n    animation.target = target;\n    animation.key = key;\n    animation.time = -animation.delay;\n    [self animationDictionaryForTarget:target][key] = animation;\n    [self.allAnimations addObject:animation];\n}\n\n- (RVAnimation *)animationforKey:(NSString *)key forTarget:(id)target\n{\n    return [self.targetToAnimationsDictionaryMap objectForKey:target][key];\n}\n\n- (void)removeAnimationForKey:(NSString *)key fromTarget:(id)target\n{\n    NSMutableDictionary *dict = [self animationDictionaryForTarget:target];\n    RVAnimation *animation = [dict objectForKey:key];\n    if (animation) {\n        [self.allAnimations removeObject:animation];\n    }\n\n    [dict removeObjectForKey:key];\n    if (dict.count == 0) {\n        [self.targetToAnimationsDictionaryMap removeObjectForKey:target];\n    }\n}\n\n\n\n- (void)tick:(NSTimeInterval)dt\n{\n    NSMutableArray *completionBlocks = [NSMutableArray array];\n    for (RVAnimation *animation in self.allAnimations.allObjects) {\n        animation.time += dt;\n        \n        Executor executor = keyExecutorMap[animation.key];\n        NSAssert(executor, @\"Animating non animatable property %@\", animation.key);\n        \n        float time = animation.time/animation.duration;\n        time = MIN(MAX(0.0f, time), 1.0f);\n\n        float progress = curves[animation.animationCurve](time);\n        \n        executor(animation, progress);\n        \n        if (time >= 1.0f) {\n            [self removeAnimationForKey:animation.key fromTarget:animation.target];\n            if (animation.completionBlock) {\n                [completionBlocks addObject:animation.completionBlock];\n            }\n        }\n    }\n    \n    for (CompletionBlock block in completionBlocks) {\n        block();\n    }\n}\n\n- (void)setStartQuaternion:(GLKQuaternion)quaternion {}\n\n+ (void)initialize\n{\n    keyExecutorMap = @{\n                       @\"color\" : ^(RVVectorAnimation *animation, float p){\n                           [(RVLineSprite *)animation.target setColor:[animation valueForProgress:p]];\n                       },\n                       @\"burnout\" : ^(RVFloatAnimation *animation, float p){\n                           [(RVLineSprite *)animation.target setBurnout:[animation valueForProgress:p]];\n                       },\n                       @\"rotation\" : ^(RVFloatAnimation *animation, float p){\n                           [(UIView *)animation.target rv_setRotation:[animation valueForProgress:p]];\n                       },\n                       @\"alpha\" : ^(RVFloatAnimation *animation, float p){\n                           [(RVPointSprite *)animation.target setAlpha:[animation valueForProgress:p]];\n                       },\n                       @\"axisAlpha\" : ^(RVFloatAnimation *animation, float p){\n                           [(RVModelSprite *)animation.target setAxisAlpha:[animation valueForProgress:p]];\n                       },\n                       @\"scale\" : ^(RVFloatAnimation *animation, float p){\n                           [(RVPointSprite *)animation.target setScale:[animation valueForProgress:p]];\n                       },\n                       @\"extraTranslationVector\" : ^(RVVectorAnimation *animation, float p){\n                           [(RVModelSprite *)animation.target setExtraTranslationVector:[animation valueForProgress:p]];\n                       },\n                       @\"scaleVector\" : ^(RVVectorAnimation *animation, float p){\n                           [(RVModelSprite *)animation.target setScaleVector:[animation valueForProgress:p]];\n                       },\n                       @\"modelScaleVector\" : ^(RVVectorAnimation *animation, float p){\n                           [(RVModelSprite *)animation.target setModelScaleVector:[animation valueForProgress:p]];\n                       },\n                       @\"widthMultiplier\" : ^(RVFloatAnimation *animation, float p){\n                           [(RVLineSprite *)animation.target setWidthMultiplier:[animation valueForProgress:p]];\n                       },\n                       @\"startQuaternion\" : ^(RVQuaternionAnimation *animation, float p){\n                           [(RVAnimator *)animation.target setStartQuaternion:[animation valueForProgress:p]];\n                       },\n                       @\"quaternion\" : ^(RVQuaternionAnimation *animation, float p){\n                           [(RVModelSprite *)animation.target setQuaternion:[animation valueForProgress:p]];\n                       },\n                       @\"wait\" : ^(RVFloatAnimation *animation, float p){\n                       },\n                       };\n}\n\n#pragma mark - Animation curves\n\nfloat easeOut(float time)\n{\n    return - time * (time - 2.0f);\n}\n\nfloat easeIn(float time)\n{\n    return time * time;\n}\n\nfloat linear(float time)\n{\n    return time;\n}\n\nfloat easeInOut(float time)\n{\n    return time * time * (3.0f - 2.0f * time);\n}\n\nfloat easeOutQuart(float time)\n{\n    float nt = 1.0f - time;\n    \n    return 1.0f - nt*nt*nt*nt;\n}\n\n\nfloat elasticEaseOut(float t)\n{\n    return 0.7*sinf(M_PI*t*4.0f)*expf(-5.0f*t) + 1.0f - expf(-14.0f*t);\n}\n\nfloat jumpEaseIn(float t)\n{\n    return t*(t - 0.2f)/0.8f;\n}\n\nfloat jumpEaseOut(float t)\n{\n    return t*t*(5.0f - 3.75f*t - 2.5*t*t + 2.25*t*t*t);\n}\n\nfloat quinticEaseInOut(float t)\n{\n    return t*t*t*(10.0f - 15.0f*t + 6.0f*t*t);\n}\n\nfloat jelly(float t)\n{\n    return (sinf(6.0f * t * (float)M_PI) * (t - 1.0f) * (t - 1.0f)) * 0.5f + 0.5f;\n}\n\n\nstatic Curve curves[] = {\n    [RVAnimationCurveEaseInOut] = easeInOut,\n    [RVAnimationCurveEaseIn] = easeIn,\n    [RVAnimationCurveEaseOut] = easeOut,\n    [RVAnimationCurveLinear] = linear,\n    [RVAnimationCurveQuartEaseOut] = easeOutQuart,\n    [RVAnimationCurveElasticEaseOut] = elasticEaseOut,\n    [RVAnimationCurveJumpEaseIn] = jumpEaseIn,\n    [RVAnimationCurveJumpEaseOut] = jumpEaseOut,\n    [RVAnimationCurveQuinticEaseInOut] = quinticEaseInOut,\n    [RVAnimationCurveJelly] = jelly,\n    \n};\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVAxisMeshController.h",
    "content": "//\n//  RVAxisMeshController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVMeshController.h\"\n\n@interface RVAxisMeshController : RVMeshController\n\n- (void)updateBuffersWithLineSprites:(NSArray *)lineSprites;\n\n@end\n"
  },
  {
    "path": "Revolved/RVAxisMeshController.m",
    "content": "//\n//  RVAxisMeshController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAxisMeshController.h\"\n#import \"RVMeshController_Private.h\"\n\n#import \"RVLineSprite.h\"\n#import \"AxisVertex.h\"\n#import \"BCShader.h\"\n\nstatic const NSUInteger VertexLimit = 512;\nstatic const NSUInteger IndexLimit = VertexLimit * 4;\n\n\nstatic const NSUInteger VerticesInSegment = 1;\nstatic const NSUInteger IndiciesInSegment = 2;\n\n@implementation RVAxisMeshController\n\n- (void)setupVAO\n{\n    glGenVertexArraysOES(1, &_VAO);\n    glBindVertexArrayOES(_VAO);\n    \n    \n    glGenBuffers(1, &_vertexBuffer);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    glBufferData(GL_ARRAY_BUFFER, VertexLimit * sizeof(AxisVertex), NULL, GL_DYNAMIC_DRAW);\n    \n    glGenBuffers(1, &_indexBuffer);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, IndexLimit * sizeof(GLushort), NULL, GL_DYNAMIC_DRAW);\n    \n    glEnableVertexAttribArray(VertexAttribPosition);\n    glVertexAttribPointer(VertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(AxisVertex), (void *)offsetof(AxisVertex, p));\n    \n    glEnableVertexAttribArray(VertexAttribColor);\n    glVertexAttribPointer(VertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(AxisVertex), (void *)offsetof(AxisVertex, color));\n    \n    \n    glBindVertexArrayOES(0);\n}\n\n\n- (void)updateBuffersWithLineSprites:(NSArray *)lineSprites\n{\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    AxisVertex *vertexData = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    GLushort *indexData = glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    \n    GLuint totalIndicies = 0;\n    GLuint totalVertices = 0;\n    \n    for (RVLineSprite *sprite in lineSprites) {\n        NSUInteger verticesCount;\n        NSUInteger indiciesCount;\n        \n        if (![self tessellateSprite:sprite vertexData:vertexData indexData:indexData startVertexIndex:totalVertices verticesCount:&verticesCount indiciesCount:&indiciesCount]) {\n            break;\n        }\n        \n        sprite.indiciesCount = (GLuint)indiciesCount;\n        sprite.indiciesOffset = totalIndicies;\n        \n        totalIndicies += indiciesCount;\n        totalVertices += verticesCount;\n        \n        vertexData += verticesCount;\n        indexData += indiciesCount;\n    }\n    \n    \n    _indiciesCount = totalIndicies;\n    \n    glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);\n    glUnmapBufferOES(GL_ARRAY_BUFFER);\n}\n\n- (BOOL)tessellateSprite:(RVLineSprite *)sprite\n              vertexData:(AxisVertex *)vertexData\n               indexData:(GLushort *)indexData\n        startVertexIndex:(NSUInteger)startVertex\n           verticesCount:(out NSUInteger *)verticesCount\n           indiciesCount:(out NSUInteger *)indiciesCount\n{\n    AxisVertex v[VerticesInSegment];\n    GLushort i[IndiciesInSegment];\n    \n    NSUInteger totalIndicies = 0;\n    NSUInteger totalVertices = 0;\n    \n    GLKVector3 color = sprite.color;\n    v[0].color = GLKVector4Make(0.0, 0.0, 0.0, MIN(1.0f, 1.1f - color.r));\n    \n    NSUInteger tesselationSegments = sprite.tesselationSegments;\n    SegmentTesselator tessalator = sprite.tesselator;\n    \n    if (startVertex + (tesselationSegments + 1) * VerticesInSegment > VertexLimit) {\n        return NO;\n    }\n    \n    for (int seg = 0; seg < tesselationSegments + 1; seg++) {\n        \n        SegmentTesselation tess = tessalator((double)seg/(double)tesselationSegments);\n        v[0].p = GLKVector3Make(tess.p.x, tess.p.y, 0.0f);\n        \n        memcpy(vertexData, v, sizeof(v));\n        vertexData += VerticesInSegment;\n        totalVertices += VerticesInSegment;\n    }\n    \n    for (int seg = 0; seg < tesselationSegments; seg++) {\n        \n        i[0] = startVertex + 0;\n        i[1] = startVertex + 1;\n        \n        memcpy(indexData, i, sizeof(i));\n        indexData += IndiciesInSegment;\n        totalIndicies += IndiciesInSegment;\n        \n        startVertex += VerticesInSegment;\n    }\n    \n    *verticesCount = totalVertices;\n    *indiciesCount = totalIndicies;\n    \n    return YES;\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVAxisShader.fsh",
    "content": "\nvarying lowp vec4 colorVarying;\n\nvoid main()\n{\n    gl_FragColor = colorVarying;\n}\n\n"
  },
  {
    "path": "Revolved/RVAxisShader.h",
    "content": "//\n//  RVAxisShader.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"BCShader.h\"\n\n@interface RVAxisShader : BCShader\n\n@property (nonatomic) GLint alphaUniform;\n@property (nonatomic) GLint viewProjectionModelMatrixUniform;\n\n@end\n"
  },
  {
    "path": "Revolved/RVAxisShader.m",
    "content": "//\n//  RVAxisShader.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAxisShader.h\"\n\n@implementation RVAxisShader\n\n- (void)bindAttributeLocations\n{\n    glBindAttribLocation(self.program, VertexAttribPosition, \"position\");\n    glBindAttribLocation(self.program, VertexAttribColor, \"color\");\n}\n\n- (void)getUniformLocations\n{\n    self.alphaUniform = glGetUniformLocation(self.program, \"axisAlpha\");\n    self.viewProjectionModelMatrixUniform = glGetUniformLocation(self.program, \"viewProjectionModelMatrix\");\n}\n\n- (NSString *)shaderName\n{\n    return @\"RVAxisShader\";\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVAxisShader.vsh",
    "content": "\nattribute vec4 position;\nattribute vec4 color;\n\nvarying vec4 colorVarying;\n\nuniform mat4 viewProjectionModelMatrix;\nuniform float axisAlpha;\n\nvoid main()\n{\n    colorVarying = color;\n    colorVarying.a *= axisAlpha;\n    \n    gl_Position = viewProjectionModelMatrix * position;\n}\n\n"
  },
  {
    "path": "Revolved/RVAxisSprite.h",
    "content": "//\n//  RVAxisSprite.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSprite.h\"\n\n@interface RVAxisSprite : RVSprite\n\n@property (nonatomic) float alpha;\n@property (nonatomic) GLKQuaternion quaternion;\n\n@end\n"
  },
  {
    "path": "Revolved/RVAxisSprite.m",
    "content": "//\n//  RVAxisSprite.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAxisSprite.h\"\n\n@implementation RVAxisSprite\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVBendTutorialPage.h",
    "content": "//\n//  RVBendTutorialPage.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialPage.h\"\n\n@interface RVBendTutorialPage : RVTutorialPage\n\n@end\n"
  },
  {
    "path": "Revolved/RVBendTutorialPage.m",
    "content": "//\n//  RVBendTutorialPage.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVBendTutorialPage.h\"\n\n@interface RVBendTutorialPage()\n\n@property (weak, nonatomic) IBOutlet UIImageView *lineBend1;\n@property (weak, nonatomic) IBOutlet UIImageView *lineBend2;\n@property (weak, nonatomic) IBOutlet UIImageView *lineBend3;\n@property (weak, nonatomic) IBOutlet UIImageView *lineBend4;\n@property (weak, nonatomic) IBOutlet UIImageView *lineBend5;\n\n@property (nonatomic, strong) NSArray *lines;\n\n@end\n\n@implementation RVBendTutorialPage\n\n- (void)awakeFromNib\n{\n    [super awakeFromNib];\n    \n    self.lines = @[self.lineBend1,\n                   self.lineBend2,\n                   self.lineBend3,\n                   self.lineBend4,\n                   self.lineBend5];\n}\n\n- (NSString *)descriptionString\n{\n    return @\"...drag handles to change its shape\";\n}\n\n\n- (void)setDisplayPercent:(float)displayPercent\n{\n    [super setDisplayPercent:displayPercent];\n    \n    displayPercent -= 0.4;\n    displayPercent /= 0.6;\n    \n    NSUInteger count = self.lines.count;\n    \n    [self.lines enumerateObjectsUsingBlock:^(UIView *line, NSUInteger idx, BOOL *stop) {\n\n        float probingOffset = (count - (NSInteger)idx - 1)/(float)(count - 1);\n        float probe = displayPercent + probingOffset - 1.0f;\n        \n        if (idx == 0) {\n            probe = MAX(probe, 0.0);\n        } else if (idx == count - 1) {\n            probe = MIN(probe, 0.0);\n        }\n        float progress = [self progressForPercent:probe];\n        \n        line.alpha = progress;\n    }];\n}\n\n- (float)progressForPercent:(float)percent\n{\n    float value = (-fabsf(percent) + 1.0f);\n    \n    return MIN(MAX(0.0f, value), 1.0);\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVBendTutorialPage.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVBendTutorialPage\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"576\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialLineBend1\" id=\"cvr-zH-myr\">\n                    <rect key=\"frame\" x=\"193\" y=\"133\" width=\"221\" height=\"309\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialLineBend3\" id=\"BXN-JN-EDY\">\n                    <rect key=\"frame\" x=\"193\" y=\"133\" width=\"221\" height=\"309\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialLineBend5\" id=\"IVK-5L-SCV\">\n                    <rect key=\"frame\" x=\"193\" y=\"133\" width=\"237\" height=\"309\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialLineBend7\" id=\"Je0-4w-84x\">\n                    <rect key=\"frame\" x=\"193\" y=\"133\" width=\"275\" height=\"309\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialLineBend9\" id=\"ozd-SN-kbK\">\n                    <rect key=\"frame\" x=\"193\" y=\"133\" width=\"314\" height=\"309\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <outlet property=\"lineBend1\" destination=\"cvr-zH-myr\" id=\"6BT-qh-ruB\"/>\n                <outlet property=\"lineBend2\" destination=\"BXN-JN-EDY\" id=\"kfD-1F-J0g\"/>\n                <outlet property=\"lineBend3\" destination=\"IVK-5L-SCV\" id=\"ImH-GP-7EJ\"/>\n                <outlet property=\"lineBend4\" destination=\"Je0-4w-84x\" id=\"mxl-1t-rA3\"/>\n                <outlet property=\"lineBend5\" destination=\"ozd-SN-kbK\" id=\"JI9-TL-akF\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TutorialLineBend1\" width=\"442\" height=\"618\"/>\n        <image name=\"TutorialLineBend3\" width=\"442\" height=\"618\"/>\n        <image name=\"TutorialLineBend5\" width=\"474\" height=\"618\"/>\n        <image name=\"TutorialLineBend7\" width=\"550\" height=\"618\"/>\n        <image name=\"TutorialLineBend9\" width=\"628\" height=\"618\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVColorPicker.h",
    "content": "//\n//  RVColorPicker.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 14.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"Color.h\"\n\n@interface RVColorPicker : UIControl\n\n@property (nonatomic, readonly) BOOL expanded;\n@property (nonatomic) NSUInteger selectedColorIndex;\n- (void)setSelectedColorIndex:(NSUInteger)selectedColorIndex animated:(BOOL)animated;\n\n\n\n- (void)expandAnimated:(BOOL)animated;\n- (void)collapseAnimated:(BOOL)animated;\n\n@end\n"
  },
  {
    "path": "Revolved/RVColorPicker.m",
    "content": "//\n//  RVColorPicker.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 14.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVColorPicker.h\"\n#import \"RVColorProvider.h\"\n#import \"RVColorPickerButton.h\"\n#import <QuartzCore/QuartzCore.h>\n\n\nstatic const CGFloat FlowerRadius = 22.0f;\nstatic const CGFloat CenterPieceRadius = 30.0f;\nstatic const CGFloat ExpandedRadius = 94.0f;\nstatic const CGFloat TotalRadius = ExpandedRadius + FlowerRadius;\n\n\nstatic const CGFloat CollapsedTopOffset = 40.0f;\nstatic const CGFloat ExpandedTopOffset = 160.0f;\n\n\n@interface RVColorPicker()\n\n@property (nonatomic, strong) UIView *rootContainer;\n@property (nonatomic, strong) UIButton *centerPiece;\n@property (nonatomic, strong) UIView *centerPieceColorView;\n\n@property (nonatomic, strong) NSArray *lollipops;\n@property (nonatomic, strong) NSArray *stems;\n@property (nonatomic, strong) NSArray *flowers;\n\n@end\n\n\n@implementation RVColorPicker\n\n\n\n- (id)initWithFrame:(CGRect)frame\n{\n    self = [super initWithFrame:frame];\n    if (self) {\n        [self commonInit];\n    }\n    return self;\n}\n\n- (id)initWithCoder:(NSCoder *)aDecoder\n{\n    self = [super initWithCoder:aDecoder];\n    if (self) {\n        [self commonInit];\n    }\n    return self;\n}\n\n- (void)commonInit\n{\n    self.backgroundColor = [UIColor clearColor];\n    //self.layer.speed = 0.1;\n    \n    [self addTarget:self action:@selector(touchedUp) forControlEvents:UIControlEventTouchUpInside];\n    [self addTarget:self action:@selector(touchedUp) forControlEvents:UIControlEventTouchUpOutside];\n    \n    self.rootContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2.0 * TotalRadius, 2.0 * TotalRadius)];\n    self.rootContainer.center = CGPointMake(self.bounds.size.width/2.0, CollapsedTopOffset);\n    self.rootContainer.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;\n    [self addSubview:self.rootContainer];\n    \n    NSMutableArray *lollipops = [NSMutableArray array];\n    NSMutableArray *stems = [NSMutableArray array];\n    NSMutableArray *flowers = [NSMutableArray array];\n    \n    \n    for (int i = 0; i < ColorCount; i++) {\n        \n        UIView *lollipop = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2.0 * FlowerRadius, TotalRadius)];\n        lollipop.layer.anchorPoint = CGPointMake(0.5, 1.0);\n        lollipop.backgroundColor = [UIColor clearColor];\n        lollipop.center = CGPointMake(TotalRadius, TotalRadius);\n        lollipop.transform = CGAffineTransformMakeRotation(i * 2.0 * M_PI/ColorCount);\n        [lollipops addObject:lollipop];\n        \n        UIImageView *stem = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"Stem\"]];\n        stem.layer.anchorPoint = CGPointMake(0.5, 1.0);\n        stem.center = CGPointMake(FlowerRadius, TotalRadius);\n        [stems addObject:stem];\n        \n        UIButton *flower = [[RVColorPickerButton alloc] initWithFrame:CGRectMake(0, 0, 2.0 * FlowerRadius, 2.0 * FlowerRadius)];\n        flower.backgroundColor = [RVColorProvider colorForColorIndex:i];\n        flower.layer.cornerRadius = FlowerRadius;\n        flower.center = CGPointMake(FlowerRadius, TotalRadius);\n        flower.tag = i;\n        [flower addTarget:self action:@selector(masterColorTouchUp:) forControlEvents:UIControlEventTouchUpInside];\n        [flowers addObject:flower];\n        \n        [self.rootContainer addSubview:lollipop];\n        [lollipop addSubview:stem];\n        [lollipop addSubview:flower];\n    }\n    \n    self.centerPiece = [[RVColorPickerButton alloc] initWithFrame:CGRectMake(0, 0, 2.0 * CenterPieceRadius, 2.0 * CenterPieceRadius)];\n    self.centerPiece.center = CGPointMake(TotalRadius, TotalRadius);\n    self.centerPiece.layer.cornerRadius = CenterPieceRadius;\n    self.centerPiece.backgroundColor = [UIColor redColor];\n    [self.centerPiece addTarget:self action:@selector(centerPieceTap:) forControlEvents:UIControlEventTouchUpInside];\n    [self.rootContainer addSubview:self.centerPiece];\n    \n    self.centerPieceColorView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2.0 * CenterPieceRadius, 2.0 * CenterPieceRadius)];\n    self.centerPieceColorView.layer.cornerRadius = CenterPieceRadius;\n    self.centerPieceColorView.backgroundColor = [UIColor clearColor];\n    self.centerPieceColorView.userInteractionEnabled = NO;\n    [self.centerPiece addSubview:self.centerPieceColorView];\n    \n    self.lollipops = lollipops;\n    self.stems = stems;\n    self.flowers = flowers;\n    \n    _selectedColorIndex = NSNotFound; //forcing refresh on setter\n    self.selectedColorIndex = 0;\n    [self collapseAnimated:NO];\n}\n\n- (void)layoutSubviews\n{\n    if (self.expanded) {\n        [self expandAnimated:NO];\n    } else {\n        [self collapseAnimated:NO];\n    }\n}\n\n\n- (void)centerPieceTap:(UIButton *)sender\n{\n    if (self.expanded) {\n        [self collapseAnimated:YES];\n    } else {\n        [self expandAnimated:YES];\n    }\n}\n\n- (void)setSelectedColorIndex:(NSUInteger)selectedColorIndex\n{\n    [self setSelectedColorIndex:selectedColorIndex animated:NO];\n}\n\n- (void)setSelectedColorIndex:(NSUInteger)selectedColorIndex animated:(BOOL)animated\n{\n    selectedColorIndex = MIN(ColorCount - 1, selectedColorIndex);\n    \n    if (_selectedColorIndex == selectedColorIndex) {\n        return;\n    }\n    _selectedColorIndex = selectedColorIndex;\n    \n    self.centerPieceColorView.transform = CGAffineTransformMakeScale(0.01, 0.01);\n    self.centerPieceColorView.backgroundColor = [RVColorProvider colorForColorIndex:selectedColorIndex];\n    self.centerPieceColorView.alpha = 0.4f;\n    [UIView animateWithDuration:animated ? 0.2 : 0.0 animations:^{\n        self.centerPieceColorView.transform = CGAffineTransformIdentity;\n        self.centerPieceColorView.alpha = 1.0f;\n    } completion:^(BOOL finished) {\n        self.centerPiece.backgroundColor = [RVColorProvider colorForColorIndex:selectedColorIndex];\n        self.centerPieceColorView.alpha = 0.0f;\n    }];\n}\n\n\n- (void)touchedUp\n{\n    [self collapseAnimated:YES];\n}\n\n- (void)masterColorTouchUp:(UIView *)sender\n{\n    if (self.expanded) {\n        \n        [self setSelectedColorIndex:sender.tag animated:YES];\n        [self sendActionsForControlEvents:UIControlEventValueChanged];\n        [self collapseAnimated:YES];\n    } else {\n        [self expandAnimated:YES];\n    }\n}\n\n- (void)collapseAnimated:(BOOL)animated\n{\n    const CGFloat CollapsedScale = 0.3;\n    \n    const NSTimeInterval FirstStepDelayVariaton = 0.15;\n    \n    const NSTimeInterval WitherDuration = 0.3;\n    const NSTimeInterval WitherDamping = 1.0;\n    const NSTimeInterval WitherVelocity = -2.0;\n    \n    const NSTimeInterval ShrinkDuration = 0.15;\n    const NSTimeInterval ShrinkDamping = 1.0;\n    const NSTimeInterval ShrinkVelocity = 0.0;\n    \n    const NSTimeInterval HopDuration = 0.45;\n    const NSTimeInterval HopDelay = 0.1;\n    const NSTimeInterval HopDamping = 1.0;\n    const NSTimeInterval HopVelocity = -5.0;\n    \n    _expanded = NO;\n    \n    [UIView animateWithDuration:animated ? HopDuration : 0.0\n                          delay:animated ? HopDelay: 0.0\n         usingSpringWithDamping:HopDamping\n          initialSpringVelocity:HopVelocity\n                        options:UIViewAnimationOptionAllowUserInteraction\n                     animations:^{\n                         self.centerPiece.transform = CGAffineTransformMakeScale(FlowerRadius/CenterPieceRadius, FlowerRadius/CenterPieceRadius);\n                         self.rootContainer.transform = CGAffineTransformIdentity;\n                     }\n                     completion:NULL];\n    \n    for (int i = 0; i < ColorCount; i++) {\n        const NSTimeInterval delay = drand48() * FirstStepDelayVariaton;\n        \n        UIView *stem = self.stems[i];\n        UIView *flower = self.flowers[i];\n        \n        [UIView animateWithDuration:animated ? WitherDuration : 0.0\n                              delay:animated ? delay : 0.0\n             usingSpringWithDamping:WitherDamping\n              initialSpringVelocity:WitherVelocity\n                            options:UIViewAnimationOptionAllowUserInteraction\n                         animations:^{\n                             stem.transform = CGAffineTransformIdentity;\n                             flower.center = CGPointMake(FlowerRadius, TotalRadius);\n                         } completion:NULL];\n        \n        [UIView animateWithDuration:animated ? ShrinkDuration : 0.0\n                              delay:animated ? delay : 0.0\n             usingSpringWithDamping:ShrinkDamping\n              initialSpringVelocity:ShrinkVelocity\n                            options:UIViewAnimationOptionAllowUserInteraction\n                         animations:^{\n                             flower.transform = CGAffineTransformMakeScale(0.8f * CollapsedScale, CollapsedScale);\n                         } completion:NULL];\n        \n        \n    }\n}\n\n\n- (void)expandAnimated:(BOOL)animated\n{\n    const NSTimeInterval DropDuration = 0.45;\n    const NSTimeInterval DropDamping = 0.78;\n    const NSTimeInterval DropVelocity = 12.0;\n    \n    \n    const NSTimeInterval SecondStepDelayVariaton = 0.2;\n    \n    const NSTimeInterval ExpandDelay = 0.06;\n    const NSTimeInterval ExpandDuration = 0.4;\n    const NSTimeInterval ExpandDamping = 0.65;\n    const NSTimeInterval ExpandVelocity = 10.0;\n    \n    const NSTimeInterval BlossomDelay = 0.13;\n    const NSTimeInterval BlossomDuration = 0.3;\n    const NSTimeInterval BlossomDamping = 0.9;\n    const NSTimeInterval BlossomVelocity = 35.0;\n    \n    _expanded = YES;\n    \n    \n    [UIView animateWithDuration:animated ? DropDuration : 0.0\n                          delay:0.0\n         usingSpringWithDamping:DropDamping\n          initialSpringVelocity:DropVelocity\n                        options:UIViewAnimationOptionAllowUserInteraction\n                     animations:^{\n                         self.centerPiece.transform = CGAffineTransformIdentity;\n                         self.rootContainer.transform = CGAffineTransformMakeTranslation(0.0, ExpandedTopOffset - CollapsedTopOffset);\n                     }\n                     completion:NULL];\n    \n    for (int i = 0; i < ColorCount; i++) {\n        const NSTimeInterval surplusDelay = drand48() * SecondStepDelayVariaton;\n        \n        UIView *stem = self.stems[i];\n        UIView *flower = self.flowers[i];\n        \n        [UIView animateWithDuration:animated ? ExpandDuration : 0.0\n                              delay:animated ? (ExpandDelay + surplusDelay) : 0.0\n             usingSpringWithDamping:ExpandDamping\n              initialSpringVelocity:ExpandVelocity\n                            options:UIViewAnimationOptionAllowUserInteraction\n                         animations:^{\n                             stem.transform = CGAffineTransformMakeScale(1.0, ExpandedRadius);\n                             flower.center = CGPointMake(FlowerRadius, FlowerRadius);\n                         } completion:NULL];\n        \n        [UIView animateWithDuration:animated ? BlossomDuration : 0.0\n                              delay:animated ? (BlossomDelay + surplusDelay) : 0.0\n             usingSpringWithDamping:BlossomDamping\n              initialSpringVelocity:BlossomVelocity\n                            options:UIViewAnimationOptionAllowUserInteraction\n                         animations:^{\n                             flower.transform = CGAffineTransformIdentity;\n                         } completion:NULL];\n    }\n}\n\n\n- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event\n{\n    UIView *hitView = [super hitTest:point withEvent:event];\n    \n    if (hitView == self && !_expanded) {\n        return nil;\n    }\n    \n    \n    return hitView;\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVColorPickerButton.h",
    "content": "//\n//  RVColorPickerButton.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 06.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVColorPickerButton : UIButton\n\n@end\n"
  },
  {
    "path": "Revolved/RVColorPickerButton.m",
    "content": "//\n//  RVColorPickerButton.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 06.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVColorPickerButton.h\"\n\n@implementation RVColorPickerButton\n\n- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event\n{\n    const CGFloat Surplus = 7.0f;\n    \n    CGSize size = self.bounds.size;\n    CGFloat radius = MIN(size.width, size.height)/2.0f;\n    \n    point.x -= radius;\n    point.y -= radius;\n    \n    CGFloat r = radius + Surplus;\n    \n    return point.x*point.x + point.y*point.y <= r * r;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVColorProvider.h",
    "content": "//\n//  RVColorProvider.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 18.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\nextern const NSUInteger ColorCount;\n\n@interface RVColorProvider : NSObject\n\n+ (UIColor *)colorForColorIndex:(NSUInteger)colorIndex;\n+ (GLKVector3)vectorForColorIndex:(NSUInteger)colorIndex;\n+ (GLKVector3)vectorForDesaturatedColorIndex:(NSUInteger)colorIndex;\n\n+ (GLKVector3)vectorForBackgroundColor;\n+ (GLKVector3)vectorForAxisColor;\n\n+ (NSString *)mtlString;\n\n@end\n"
  },
  {
    "path": "Revolved/RVColorProvider.m",
    "content": "//\n//  RVColorProvider.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 18.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVColorProvider.h\"\n\n\nconst NSUInteger ColorCount = 12;\n\nstatic const NSUInteger ColorValues[ColorCount] = {\n    0xed4c54,\n    0xf58c58,\n    0xfebe4d,\n    0xf1d948,\n    0x98cc3d,\n    0x47b24f,\n    0x35b299,\n    0x368ab4,\n    0x345fa3,\n    0x8045ba,\n    0xb440b1,\n    0xb53678,\n};\n\nstatic UIColor *colors[ColorCount];\nstatic GLKVector3 vectors[ColorCount];\nstatic GLKVector3 desaturatedVectors[ColorCount];\n\n@implementation RVColorProvider\n\n\n+ (void)initialize\n{\n    for (int i = 0; i < ColorCount; i++) {\n        colors[i] = [self colorFromHex:ColorValues[i]];\n        vectors[i] = [self vectorFromHex:ColorValues[i]];\n        desaturatedVectors[i] = [self vectorForColor:[self desaturatedColor:colors[i]]];\n    }\n}\n\n+ (UIColor *)colorFromHex:(NSUInteger)hex\n{\n    return [UIColor colorWithRed:((float)((hex & 0xFF0000) >> 16))/255.0\n                           green:((float)((hex & 0x00FF00) >> 8))/255.0\n                            blue:((float)((hex & 0x0000FF) >> 0))/255.0 alpha:1.0];\n}\n\n+ (UIColor *)desaturatedColor:(UIColor *)color\n{\n    CGFloat hue, saturation, brightness, alpha;\n    [color getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha];\n    \n    return [UIColor colorWithHue:hue saturation:saturation * 0.1 brightness:brightness * 0.8 alpha:alpha];\n}\n\n+ (GLKVector3)vectorForColor:(UIColor *)color\n{\n    CGFloat red, green, blue, alpha;\n    [color getRed:&red green:&green blue:&blue alpha:&alpha];\n    \n    return GLKVector3Make(red, green, blue);\n}\n\n+ (GLKVector3)vectorFromHex:(NSUInteger)hex\n{\n    return GLKVector3Make((float)((hex & 0xFF0000) >> 16)/255.0,\n                          (float)((hex & 0x00FF00) >> 8)/255.0,\n                          (float)((hex & 0x0000FF) >> 0)/255.0);\n}\n\n\n+ (UIColor *)colorForColorIndex:(NSUInteger)colorIndex\n{\n    return colors[colorIndex];\n}\n\n+ (GLKVector3)vectorForColorIndex:(NSUInteger)colorIndex\n{\n    return vectors[colorIndex];\n}\n\n+ (GLKVector3)vectorForDesaturatedColorIndex:(NSUInteger)colorIndex\n{\n    return desaturatedVectors[colorIndex];\n}\n\n+ (GLKVector3)vectorForBackgroundColor\n{\n    const float shade = 0.93f;\n    return GLKVector3Make(shade, shade, shade);\n}\n\n+ (GLKVector3)vectorForAxisColor\n{\n    const float shade = 0.72f;\n    return GLKVector3Make(shade, shade, shade);\n}\n\n+ (NSString *)mtlString\n{\n    NSMutableString *string = [NSMutableString string];\n    \n    for (int i = 0; i < ColorCount; i++) {\n        [string appendFormat:@\"newmtl mat%d\\n\", i];\n        \n        GLKVector3 c = [self vectorForColorIndex:i];\n        GLKVector3 Ka = c;\n        GLKVector3 Kd = c;\n        \n        [string appendFormat:@\"Ka %g %g %g\\n\", Ka.x, Ka.y, Ka.z];\n        [string appendFormat:@\"Kd %g %g %g\\n\", Kd.x, Kd.y, Kd.z];\n        [string appendFormat:@\"Ks %g %g %g\\n\", 0.0f, 0.0f, 0.0f];\n        \n        [string appendString:@\"d 1\\nillum 2\\n\\n\"];\n    }\n    \n    return string;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVControlPoint.h",
    "content": "//\n//  RVControlPoint.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPoint.h\"\n\n@interface RVControlPoint : RVPoint\n\n@end\n"
  },
  {
    "path": "Revolved/RVControlPoint.m",
    "content": "//\n//  RVControlPoint.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVControlPoint.h\"\n\n@implementation RVControlPoint\n\n- (PointType)type\n{\n    return PointTypeControl;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVCreditsViewController.h",
    "content": "//\n//  RVCreditsViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVCreditsViewController : UIViewController\n\n- (void)present;\n\n@end\n"
  },
  {
    "path": "Revolved/RVCreditsViewController.m",
    "content": "//\n//  RVCreditsViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVCreditsViewController.h\"\n\n#import <MessageUI/MessageUI.h>\n#import \"MFMailComposeViewController+SendIfPossible.h\"\n\ntypedef NS_ENUM(NSInteger, TwitterClient) {\n    TwitterClientTwitterrific,\n    TwitterClientTweetbot,\n    TwitterClientTwitter,\n};\n\n\nstatic NSString * const TwitterNames[] = {\n    [TwitterClientTwitterrific] = @\"Twitterrific\",\n    [TwitterClientTweetbot] = @\"Tweetbot\",\n    [TwitterClientTwitter] = @\"Twitter\",\n};\n\n@interface RVCreditsViewController () <MFMailComposeViewControllerDelegate>\n\n@property (nonatomic, strong) NSArray *displayedTwitterClients;\n@property (weak, nonatomic) IBOutlet UIControl *backgroundView;\n@property (weak, nonatomic) IBOutlet UIView *containerView;\n@property (weak, nonatomic) IBOutlet UIButton *twitterButton;\n@property (weak, nonatomic) IBOutlet UIButton *emailButton;\n\n@end\n\n@implementation RVCreditsViewController\n\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    self.twitterButton.exclusiveTouch = YES;\n    self.emailButton.exclusiveTouch = YES;\n    \n    self.view.hidden = YES;\n    self.containerView.backgroundColor = [UIColor rv_backgroundColor];\n    self.backgroundView.backgroundColor = [UIColor rv_dimColor];\n\n}\n\n\n- (void)present\n{\n    const NSTimeInterval BackgroundDuration = 0.2;\n    const NSTimeInterval SlideDelay = 0.1;\n    const NSTimeInterval SlideDuration = 0.5;\n    \n    \n    self.view.hidden = NO;\n    self.backgroundView.alpha = 0.0f;\n    self.containerView.transform = CGAffineTransformMakeTranslation(0.0, -self.view.bounds.size.height);\n    \n    [UIView animateWithDuration:BackgroundDuration animations:^{\n        self.backgroundView.alpha = 1.0f;\n    }];\n    \n    [UIView animateWithDuration:SlideDuration delay:SlideDelay usingSpringWithDamping:0.85 initialSpringVelocity:0.0 options:0 animations:^{\n        self.containerView.transform = CGAffineTransformIdentity;\n    } completion:NULL];\n}\n\n- (void)dismiss\n{\n    const NSTimeInterval BackgroundDuration = 0.2;\n    const NSTimeInterval BackgroundDelay = 0.3;\n    const NSTimeInterval SlideDuration = 0.5;\n    \n    [UIView animateWithDuration:BackgroundDuration delay:BackgroundDelay options:0 animations:^{\n        self.backgroundView.alpha = 0.0f;\n    } completion:^(BOOL finished) {\n        self.view.hidden = YES;\n    }];\n    \n    \n    [UIView animateWithDuration:SlideDuration delay:0.0 usingSpringWithDamping:1.0 initialSpringVelocity:-5.0 options:0 animations:^{\n        self.containerView.transform = CGAffineTransformMakeTranslation(0.0, -self.view.bounds.size.height);\n    } completion:NULL];\n}\n\n- (IBAction)backgroundTouched:(UIControl *)sender\n{\n    [self dismiss];\n}\n\n\n- (IBAction)emailButtonTapped:(UIButton *)sender\n{\n    if ([MFMailComposeViewController rv_canSendEmailIfNotShowAlert]) {\n        MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];\n        mailer.mailComposeDelegate = self;\n        \n        [mailer setSubject:@\"Hello!\"];\n        [mailer setToRecipients:@[@\"bartosz@ciechanowski.me\"]];\n        [self presentViewController:mailer animated:YES completion:NULL];\n    }\n}\n\n- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error\n{\n    if (result == MFMailComposeResultFailed) {\n        [MFMailComposeViewController rv_showDefaultFailAlertWithError:error];\n    } else {\n        [self dismissViewControllerAnimated:YES completion:NULL];\n    }\n}\n\n\n- (IBAction)twitterButtonTapped:(UIButton *)sender\n{\n    NSArray *clients = [self twitterClients];\n    \n    if (clients.count == 0) {\n        [[UIApplication sharedApplication] openURL:[self safariAppURL]];\n        return;\n    }\n    \n    if (clients.count == 1) {\n        [[UIApplication sharedApplication] openURL:[self urlForClient:[[clients firstObject] integerValue]]];\n        return;\n    }\n    \n    self.displayedTwitterClients = clients;\n    \n    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@\"Multiple Twitter Clients\" message:@\"Which one would you like to use?\" delegate:self cancelButtonTitle:@\"Cancel\" otherButtonTitles:nil];\n    for (NSNumber *clientNumber in clients) {\n        [alert addButtonWithTitle:TwitterNames[[clientNumber integerValue]]];\n    }\n    \n    [alert show];\n}\n\n\n- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex\n{\n    if (buttonIndex == alertView.cancelButtonIndex) {\n        return;\n    }\n    \n    TwitterClient client = [self.displayedTwitterClients[buttonIndex - 1] integerValue];\n    [[UIApplication sharedApplication] openURL:[self urlForClient:client]];\n}\n\n- (NSArray *)twitterClients\n{\n    NSMutableArray *clients = [NSMutableArray array];\n    \n    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@\"twitterrific://\"]]) {\n        [clients addObject:@(TwitterClientTwitterrific)];\n    }\n    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@\"tweetbot://\"]]) {\n        [clients addObject:@(TwitterClientTweetbot)];\n    }\n    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@\"twitter://\"]]) {\n        [clients addObject:@(TwitterClientTwitter)];\n    }\n\n    \n    return clients;\n}\n\n\n- (NSURL *)urlForClient:(TwitterClient)client\n{\n    switch (client) {\n        case TwitterClientTweetbot:\n            return [NSURL URLWithString:@\"tweetbot:///user_profile/BCiechanowski\"];\n        case TwitterClientTwitter:\n            return [NSURL URLWithString:@\"twitter://user?screen_name=BCiechanowski\"];\n        case TwitterClientTwitterrific:\n            return [NSURL URLWithString:@\"twitterrific:///profile?screen_name=BCiechanowski\"];\n            \n        default:\n            break;\n    }\n    return nil;\n}\n\n- (NSURL *)safariAppURL\n{\n    return [NSURL URLWithString:@\"https://twitter.com/BCiechanowski\"];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVCreditsViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"5023\" systemVersion=\"12F45\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3733\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVCreditsViewController\">\n            <connections>\n                <outlet property=\"backgroundView\" destination=\"KYd-qv-ZHl\" id=\"TwK-kl-0NA\"/>\n                <outlet property=\"containerView\" destination=\"NcQ-qU-YGN\" id=\"5Pd-RU-Cei\"/>\n                <outlet property=\"emailButton\" destination=\"4q5-1w-r6n\" id=\"VSH-J9-SyT\"/>\n                <outlet property=\"twitterButton\" destination=\"IKA-rK-Nwx\" id=\"19k-50-q3m\"/>\n                <outlet property=\"view\" destination=\"2\" id=\"3\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" id=\"2\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"KYd-qv-ZHl\" userLabel=\"Background\" customClass=\"UIControl\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                    <subviews>\n                        <view contentMode=\"scaleToFill\" id=\"NcQ-qU-YGN\" userLabel=\"Container\">\n                            <rect key=\"frame\" x=\"362\" y=\"209\" width=\"300\" height=\"350\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                            <subviews>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"IKA-rK-Nwx\">\n                                    <rect key=\"frame\" x=\"80\" y=\"275\" width=\"50\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"Twitter\"/>\n                                    <connections>\n                                        <action selector=\"twitterButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"4b9-Vp-0uV\"/>\n                                    </connections>\n                                </button>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"4q5-1w-r6n\">\n                                    <rect key=\"frame\" x=\"170\" y=\"275\" width=\"50\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"MailButton\"/>\n                                    <connections>\n                                        <action selector=\"emailButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"d5B-6J-KLc\"/>\n                                    </connections>\n                                </button>\n                                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"CreditsText\" id=\"Nth-ab-68h\">\n                                    <rect key=\"frame\" x=\"38\" y=\"56\" width=\"224\" height=\"158\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                </imageView>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"0.9379276916\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        </view>\n                    </subviews>\n                    <color key=\"backgroundColor\" white=\"0.14999999999999999\" alpha=\"0.80000000000000004\" colorSpace=\"calibratedWhite\"/>\n                    <connections>\n                        <action selector=\"backgroundTouched:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"V2H-BY-9Ib\"/>\n                        <action selector=\"backgroundTouched:\" destination=\"-1\" eventType=\"touchUpOutside\" id=\"ciu-0Z-HNl\"/>\n                    </connections>\n                </view>\n            </subviews>\n            <simulatedStatusBarMetrics key=\"simulatedStatusBarMetrics\" statusBarStyle=\"lightContent\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"CreditsText\" width=\"224\" height=\"158\"/>\n        <image name=\"MailButton\" width=\"34\" height=\"24\"/>\n        <image name=\"Twitter\" width=\"38\" height=\"32\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Revolved/RVDeleteView.h",
    "content": "//\n//  RVDeleteView.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 16.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVDeleteView : UIView\n\n@property (nonatomic) float percentOpen;\n\n- (void)appear;\n- (void)disappearWithDeleteAnimation:(BOOL)shouldAnimateDelete;\n\n@end\n"
  },
  {
    "path": "Revolved/RVDeleteView.m",
    "content": "//\n//  RVDeleteView.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 16.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVDeleteView.h\"\n\n@interface RVDeleteView()\n\n@property (nonatomic, strong) UIView *container;\n\n@property (nonatomic, strong) UIImageView *canImageView;\n@property (nonatomic, strong) UIImageView *lidImageView;\n\n@end\n\n\n@implementation RVDeleteView\n\n\n- (id)initWithFrame:(CGRect)frame\n{\n    self = [super initWithFrame:frame];\n    if (self) {\n        \n        self.container = [[UIView alloc] initWithFrame:CGRectZero];\n        self.container.clipsToBounds = NO;\n        self.container.backgroundColor = [UIColor clearColor];\n        [self addSubview:self.container];\n        \n        self.canImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"TrashCan\"]];\n        [self.container addSubview:self.canImageView];\n        \n        self.lidImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"TrashCanLid\"]];\n        [self.container addSubview:self.lidImageView];\n    }\n    return self;\n}\n\n- (void)layoutSubviews\n{\n    const CGPoint LidCoverOffset = CGPointMake(-1, 2);\n    \n    CGRect bounds = self.bounds;\n    \n    self.container.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));\n    self.canImageView.center = CGPointZero;\n    CGPoint canOrigin = self.canImageView.frame.origin;\n    CGPoint lidCenter = CGPointMake(canOrigin.x + LidCoverOffset.x, canOrigin.y + LidCoverOffset.y);\n    self.lidImageView.center = lidCenter;\n}\n\n- (UIColor *)onColor\n{\n    return [UIColor colorWithHue:0.0 saturation:0.82 brightness:0.89 alpha:0.85];\n}\n\n- (UIColor *)offColor\n{\n    return [UIColor colorWithWhite:0.75 alpha:0.85];\n}\n\n\n- (void)setPercentOpen:(float)percentOpen\n{\n    percentOpen = MIN(MAX(0.0, percentOpen), 1.0);\n    \n    if (percentOpen == 1.0) {\n        [UIView animateWithDuration:0.2 animations:^{\n            self.backgroundColor = [self onColor];\n        }];\n    } else {\n        [UIView animateWithDuration:0.2 animations:^{\n            self.backgroundColor = [self offColor];\n        }];\n    }\n    _percentOpen = percentOpen;\n    \n    self.lidImageView.transform = CGAffineTransformMakeRotation(-M_PI * _percentOpen);\n}\n\n- (void)appear\n{\n    [UIView animateWithDuration:0.2 animations:^{\n        self.alpha = 1.0f;\n    }];\n}\n\n- (void)disappearWithDeleteAnimation:(BOOL)shouldAnimateDelete\n{\n    const float Scale = 1.2f;\n    \n    if (shouldAnimateDelete) {\n        [UIView animateWithDuration:0.2 animations:^{\n            self.container.transform = CGAffineTransformMakeScale(Scale, Scale);\n            self.container.alpha = 0.5;\n            self.alpha = 0.0f;\n        } completion:^(BOOL finished) {\n            [UIView animateWithDuration:0.2 animations:^{\n                self.container.transform = CGAffineTransformIdentity;\n                self.container.alpha = 1.0;\n                \n                self.backgroundColor = [self offColor];\n            }];\n        }];\n    } else {\n        [UIView animateWithDuration:_percentOpen * 0.2 animations:^{\n            self.lidImageView.transform = CGAffineTransformIdentity;\n        } completion:^(BOOL finished) {\n            if (finished) {\n                [UIView animateWithDuration:0.2 animations:^{\n                    self.alpha = 0.0f;\n                }];\n            }\n        }];\n    }\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVDrawController.h",
    "content": "//\n//  DrawController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"Color.h\"\n\n@class RVSegment, RVPoint, RVGuideline, RVControlPoint;\n@protocol DrawControllerDelegate;\n\ntypedef NS_ENUM(NSInteger, DrawControllerState) {\n    DrawControllerStateIdle,\n    DrawControllerStateDrawing,\n    DrawControllerStateSelection,\n    DrawControllerStateDraggingPoint\n};\n\n@interface RVDrawController : NSObject\n\n@property (nonatomic, weak) id<DrawControllerDelegate> delegate;\n@property (nonatomic) DrawControllerState state;\n\n@property (nonatomic, strong) NSMutableOrderedSet *segments;\n@property (nonatomic, strong, readonly) RVSegment *selectedSegment;\n\n@property (nonatomic) float rightEdge;\n@property (nonatomic) float topEdge;\n@property (nonatomic) float bottomEdge;\n\n@property (nonatomic) float evadeSquareRadius;\n@property (nonatomic) GLKVector2 topEvadeCenter;\n@property (nonatomic) GLKVector2 bottomEvadeCenter;\n\n@property (nonatomic) float snapDistanceSquared;\n@property (nonatomic) float tapDistanceSquared;\n\n\n- (void)handlePanBeginAtPosition:(GLKVector2)position firstTouchPosition:(GLKVector2)firstTouchPosition;\n- (void)handlePanContinueAtPosition:(GLKVector2)position;\n- (void)handlePanEndAtPosition:(GLKVector2)position;\n\n- (void)handleTapAtPosition:(GLKVector2)position;\n\n- (void)handleColorSelection:(NSUInteger)selectedColorIndex;\n\n\n- (void)deleteSegment:(RVSegment *)segment;\n- (void)clear;\n\n@end\n\n\n@protocol DrawControllerDelegate <NSObject>\n\n- (void)drawControllerDidSelectSegment:(RVSegment *)segment;\n- (void)drawControllerDidSelectEndPoint:(RVPoint *)endPoint;\n\n- (void)drawControllerDidTryAddButReachedSegmentLimit;\n\n- (void)drawControllerDidAddSegment:(RVSegment *)segment;\n- (void)drawControllerDidModifySegment:(RVSegment *)segment;\n- (void)drawControllerDidRecolorSegment:(RVSegment *)segment;\n- (void)drawControllerDidRemoveSegment:(RVSegment *)segment;\n\n- (void)drawControllerDidAddGuideLine:(RVGuideline *)guideline;\n- (void)drawControllerDidRemoveGuideLine:(RVGuideline *)guideline;\n\n- (void)drawControllerDidStartDraggingPoint:(RVPoint *)point;\n- (void)drawControllerDidDragPoint:(RVPoint *)point;\n- (void)drawControllerDidEndDraggingPoint:(RVPoint *)point;\n\n- (void)drawControllerDidSelectColorIndex:(NSUInteger)colorIndex;\n\n@end"
  },
  {
    "path": "Revolved/RVDrawController.m",
    "content": "//\n//  DrawController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVDrawController.h\"\n#import \"RVSegment.h\"\n#import \"RVSegmentConnection.h\"\n#import \"RVGuideline.h\"\n#import \"Geometry.h\"\n\n#import \"RVEndPoint.h\"\n#import \"RVAnchorPoint.h\"\n#import \"RVControlPoint.h\"\n\n#import \"Constants.h\"\n\n@interface RVDrawController()\n\n@property (nonatomic) NSUInteger drawingColorIndex;\n\n@property (nonatomic, strong) RVSegment *drawnSegment;\n@property (nonatomic, strong, readwrite) RVSegment *selectedSegment;\n\n@property (nonatomic, strong) RVPoint *draggedPoint;\n@property (nonatomic) GLKVector2 draggedPointOffset;\n@property (nonatomic, strong) RVGuideline *currentGuideLine;\n\n@end\n\n@implementation RVDrawController\n\n\n- (void)setSelectedSegment:(RVSegment *)selectedSegment\n{\n    if (_selectedSegment == selectedSegment) {\n        return;\n    }\n    \n    if (selectedSegment) {\n        NSUInteger segmentIndex = [self.segments indexOfObject:selectedSegment];\n        NSUInteger lastIndex = self.segments.count - 1;\n        \n        NSAssert(segmentIndex != NSNotFound, @\"SelectedSegment not in allSegments\");\n        NSAssert(self.segments.count > 0, @\"allSegments empty\");\n        \n        [self.segments moveObjectsAtIndexes:[NSIndexSet indexSetWithIndex:segmentIndex] toIndex:lastIndex];\n    }\n    _selectedSegment = selectedSegment;\n    \n    [self.delegate drawControllerDidSelectSegment:selectedSegment];\n    [self.delegate drawControllerDidSelectColorIndex:selectedSegment ? selectedSegment.colorIndex : self.drawingColorIndex];\n}\n\n- (void)deleteSegment:(RVSegment *)segment\n{\n    [RVSegmentConnection disconnectSegment:segment atSegmentEnd:SegmentEndFirst];\n    [RVSegmentConnection disconnectSegment:segment atSegmentEnd:SegmentEndSecond];\n    \n    [self.segments removeObject:segment];\n    \n    if (segment == self.selectedSegment) {\n        self.selectedSegment = nil;\n        self.state = DrawControllerStateIdle;\n    }\n    \n    [self.delegate drawControllerDidRemoveSegment:segment];\n}\n\n- (void)clear\n{\n    self.segments = nil;\n    \n    self.state = DrawControllerStateIdle;\n    \n    self.drawnSegment = nil;\n    self.draggedPoint = nil;\n    self.selectedSegment = nil;\n}\n\n- (RVGuideline *)guideLineForControlPoint:(RVControlPoint *)controlPoint\n{\n    RVSegment *segment = controlPoint.segment;\n    RVSegmentConnection *connection = [segment connectionAtSegmentEnd:controlPoint.segmentEnd];\n    \n    if (!connection) {\n        return nil;\n    }\n    \n    SegmentEnd otherEnd;\n    RVSegment *otherSegment = [connection otherSegment:segment otherEnd:&otherEnd];\n    RVPoint *otherControlPoint = [otherSegment controlPointAtSegmentEnd:otherEnd];\n    RVPoint *otherPoint = [otherSegment endPointAtSegmentEnd:otherEnd];\n    \n    GLKVector2 start = otherPoint.position;\n    GLKVector2 direction = GLKVector2Normalize(GLKVector2Subtract(start, otherControlPoint.position));\n    \n    float t = INFINITY;\n    float newT = -1.0f;\n    \n    newT = (self.topEdge - start.y)/direction.y;\n    if (newT >= 0.0f && newT < t) {\n        t = newT;\n    }\n    \n    newT = (self.bottomEdge - start.y)/direction.y;\n    if (newT >= 0.0f && newT < t) {\n        t = newT;\n    }\n    \n    newT = (-start.x)/direction.x;\n    if (newT >= 0.0f && newT < t) {\n        t = newT;\n    }\n    \n    newT = (self.rightEdge - start.x)/direction.x;\n    if (newT >= 0.0f && newT < t) {\n        t = newT;\n    }\n    \n    if (start.x <= 0.0f || start.y >= _rightEdge || start.y <= _bottomEdge || start.y >= _topEdge) {\n        t = 0.0f;\n    }\n    \n    \n    GLKVector2 scaledDirection = GLKVector2MultiplyScalar(direction, t);\n    \n    \n    RVGuideline *guideline = [RVGuideline new];\n    guideline.start = start;\n    guideline.end = GLKVector2Add(start, scaledDirection);\n    guideline.direction = direction;\n    guideline.length = GLKVector2Length(scaledDirection);\n    \n    return guideline;\n}\n\n\n#pragma mark - Segment connection\n\n- (void)snapSegment:(RVSegment *)segment bySegmentEnd:(SegmentEnd)segmentEnd nearPosition:(GLKVector2)position\n{\n    position = [self clampedPosition:position];\n    \n    NSMutableSet *staticSegments = [NSMutableSet setWithSet:self.segments.set];\n    [staticSegments removeObject:segment];\n    \n    RVEndPoint *sourcePoint = [segment endPointAtSegmentEnd:segmentEnd];\n    RVEndPoint *snapPoint = [self nearestEndPointForPosition:position amongSegments:staticSegments withDistanceSq:_snapDistanceSquared];\n    \n    if (snapPoint) {\n        RVSegmentConnection *snapPointConnection = [snapPoint.segment connectionAtSegmentEnd:snapPoint.segmentEnd];\n        \n        if (snapPointConnection) {\n            if ([snapPointConnection hasEndPoint:sourcePoint]) {\n                [sourcePoint setPosition:snapPoint.position];\n            } else {\n                [sourcePoint setPosition:position];\n            }\n        } else {\n            [RVSegmentConnection disconnectSegment:segment atSegmentEnd:segmentEnd];\n            [RVSegmentConnection connectSegment:segment bySegmentEnd:segmentEnd toSegment:snapPoint.segment atSegmentEnd:snapPoint.segmentEnd];\n            [sourcePoint setPosition:snapPoint.position];\n        }\n    } else {\n        [RVSegmentConnection disconnectSegment:segment atSegmentEnd:segmentEnd];\n        [sourcePoint setPosition:position];\n    }\n    \n    [segment adjustAnchorPoints];\n}\n\n\n#pragma mark - Event handling\n\n- (void)handlePanBeginAtPosition:(GLKVector2)position firstTouchPosition:(GLKVector2)firstTouchPosition\n{\n    if (self.state == DrawControllerStateIdle) {\n        if (self.segments.count > SegmentLimit) {\n            [self.delegate drawControllerDidTryAddButReachedSegmentLimit];\n            return;\n        }\n        \n        self.state = DrawControllerStateDrawing;\n        \n        self.drawnSegment = [[RVSegment alloc] init];\n        [self snapSegment:self.drawnSegment bySegmentEnd:SegmentEndFirst nearPosition:firstTouchPosition];\n        RVPoint *a = [self.drawnSegment endPointAtSegmentEnd:SegmentEndFirst];\n        RVPoint *b = [self.drawnSegment endPointAtSegmentEnd:SegmentEndSecond];\n        b.position = a.position;\n        self.drawnSegment.colorIndex = self.drawingColorIndex;\n        \n        [self.segments addObject:self.drawnSegment];\n        \n        [self.delegate drawControllerDidAddSegment:self.drawnSegment];\n        return;\n    }\n    \n    if (self.state == DrawControllerStateSelection) {\n        \n        RVPoint *bestPoint = [self closestPointInSet:[self.selectedSegment draggablePoints]\n                                          toPosition:firstTouchPosition\n                                        graceSquared:_tapDistanceSquared];\n        \n        if (bestPoint) {\n            self.draggedPoint = bestPoint;\n            self.draggedPointOffset = GLKVector2Subtract(position, bestPoint.position);\n            \n            self.state = DrawControllerStateDraggingPoint;\n            if (bestPoint.type == PointTypeControl) {\n                RVGuideline *guideline = [self guideLineForControlPoint:(RVControlPoint *)bestPoint];\n                if (guideline) {\n                    self.currentGuideLine = guideline;\n                    [self.delegate drawControllerDidAddGuideLine:guideline];\n                }\n            }\n            \n            [self.delegate drawControllerDidStartDraggingPoint:bestPoint];\n        }\n        return;\n    }\n}\n\n- (void)handlePanContinueAtPosition:(GLKVector2)position\n{\n    if (self.state == DrawControllerStateDrawing) {\n        \n        [self snapSegment:self.drawnSegment bySegmentEnd:SegmentEndSecond nearPosition:position];\n        [self.drawnSegment adjustAnchorPoints];\n        \n        [self.delegate drawControllerDidModifySegment:self.drawnSegment];\n        return;\n    }\n    \n    if (self.state == DrawControllerStateDraggingPoint) {\n        \n        position = GLKVector2Subtract(position, self.draggedPointOffset);\n        \n        if (self.draggedPoint.type == PointTypeControl) {\n            self.draggedPoint.position = [self snapPositionForControlPoint:(RVControlPoint *)self.draggedPoint nearPosition:position withDistanceSq:_snapDistanceSquared];\n        } else if (self.draggedPoint.type == PointTypeEnd) {\n            [self snapSegment:self.draggedPoint.segment bySegmentEnd:self.draggedPoint.segmentEnd nearPosition:position];\n        }\n        \n        [self.delegate drawControllerDidDragPoint:self.draggedPoint];\n        [self.delegate drawControllerDidModifySegment:self.draggedPoint.segment];\n        return;\n    }\n}\n\n- (void)handlePanEndAtPosition:(GLKVector2)position;\n{\n    if (self.state == DrawControllerStateDrawing) {\n        self.state = DrawControllerStateIdle;\n        self.drawnSegment = nil;\n        return;\n    }\n    \n    \n    if (self.state == DrawControllerStateDraggingPoint) {\n        self.state = DrawControllerStateSelection;\n        [self.delegate drawControllerDidEndDraggingPoint:self.draggedPoint];\n        self.draggedPoint = nil;\n        \n        if (self.currentGuideLine) {\n            [self.delegate drawControllerDidRemoveGuideLine:self.currentGuideLine];\n            self.currentGuideLine = nil;\n        }\n        \n        return;\n    }\n    \n}\n\n- (void)handleTapAtPosition:(GLKVector2)position\n{\n    if (self.state == DrawControllerStateSelection) {\n        RVPoint *hitPoint = [self closestPointInSet:[self.selectedSegment draggablePoints]\n                                         toPosition:position\n                                       graceSquared:_tapDistanceSquared];\n        \n        if (hitPoint) {\n            [self.delegate drawControllerDidSelectEndPoint:hitPoint];\n            return;\n        }\n    }\n    \n    float bestDist = INFINITY;\n    float dist;\n    RVSegment *bestSegment = nil;\n    for (RVSegment *segment in self.segments) {\n        if ((dist = [segment hitSquareDistance:position]) < bestDist) {\n            bestDist = dist;\n            bestSegment = segment;\n        }\n    }\n    \n    \n    if (bestDist < _tapDistanceSquared) {\n        if (self.state == DrawControllerStateSelection && bestSegment == self.selectedSegment) {\n            self.state = DrawControllerStateIdle;\n            self.selectedSegment = nil;\n        } else {\n            self.state = DrawControllerStateSelection;\n            self.selectedSegment = bestSegment;\n        }\n    } else {\n        self.state = DrawControllerStateIdle;\n        self.selectedSegment = nil;\n    }\n    \n}\n\n- (void)handleColorSelection:(NSUInteger)selectedColorIndex\n{\n    if (self.state == DrawControllerStateSelection || self.state == DrawControllerStateDraggingPoint) {\n        self.selectedSegment.colorIndex = selectedColorIndex;\n        [self.delegate drawControllerDidRecolorSegment:self.selectedSegment];\n        \n    } else if (self.state == DrawControllerStateIdle) {\n        self.drawingColorIndex = selectedColorIndex;\n    } else if (self.state == DrawControllerStateDrawing) {\n        self.drawnSegment.colorIndex = selectedColorIndex;\n        self.drawingColorIndex = selectedColorIndex;\n        [self.delegate drawControllerDidRecolorSegment:self.drawnSegment];\n\n    }\n}\n\n\n#pragma mark - Helpers\n\n- (GLKVector2)clampedPosition:(GLKVector2)position\n{\n    position.x = MIN(MAX(0.0, position.x), _rightEdge);\n    position.y = MIN(MAX(_bottomEdge, position.y), _topEdge);\n    \n    GLKVector2 bottomDiff = GLKVector2Subtract(position, _bottomEvadeCenter);\n    GLKVector2 topDiff = GLKVector2Subtract(position, _topEvadeCenter);\n    \n    if (GLKVector2DotProduct(bottomDiff, bottomDiff) <= _evadeSquareRadius) {\n        position.y = _bottomEvadeCenter.y + sqrtf(_evadeSquareRadius - bottomDiff.x * bottomDiff.x);\n    } else if (GLKVector2DotProduct(topDiff, topDiff) <= _evadeSquareRadius) {\n        position.y = _topEvadeCenter.y - sqrtf(_evadeSquareRadius - topDiff.x * topDiff.x);\n    }\n    \n    return position;\n}\n\n- (RVPoint *)closestPointInSet:(NSSet *)points toPosition:(GLKVector2)position graceSquared:(float)graceSquared\n{\n    float bestDist = INFINITY;\n    float dist;\n    RVPoint *bestPoint = nil;\n    \n    for (RVPoint *point in points) {\n        \n        if ((dist = [point hitSquareDistance:position]) < bestDist) {\n            bestDist = dist;\n            bestPoint = point;\n        }\n    }\n    \n    if (bestDist < graceSquared) {\n        return bestPoint;\n    }\n    \n    return nil;\n}\n\n\n\n- (GLKVector2)snapPositionForControlPoint:(RVControlPoint *)controlPoint nearPosition:(GLKVector2)position withDistanceSq:(float)distanceSq\n{\n    assert([controlPoint isKindOfClass:[RVControlPoint class]]);\n    \n    RVSegment *segment = controlPoint.segment;\n    RVAnchorPoint *anchorPoint = [segment anchorPointAtSegmentEnd:controlPoint.segmentEnd];\n    \n    if (GLKVector2DistanceSq(position, anchorPoint.position) < _snapDistanceSquared) {\n        anchorPoint.hasControlPoint = YES;\n        return anchorPoint.position;\n    }\n    anchorPoint.hasControlPoint = NO;\n    \n    if (self.currentGuideLine) {\n        float t;\n        GLKVector2 tangentPoint = ClosestPointOnSegmentForPoint(self.currentGuideLine.start, self.currentGuideLine.end, position, &t);\n        \n        if (t <= 1.0 && t >= 0.0 && GLKVector2DistanceSq(position, tangentPoint) < _snapDistanceSquared) {\n            return [self clampedPosition:tangentPoint];\n        }\n    }\n    \n    return [self clampedPosition:position];\n}\n\n- (RVEndPoint *)nearestEndPointForPosition:(GLKVector2)position amongSegments:(NSSet *)segments withDistanceSq:(float)distanceSq\n{\n    NSMutableSet *allEndPoints = [NSMutableSet setWithCapacity:segments.count * 2];\n    \n    for (RVSegment *segment in segments) {\n        for (SegmentEnd end = SegmentEndFirst; end <= SegmentEndSecond; end++) {\n            [allEndPoints addObject:[segment endPointAtSegmentEnd:end]];\n        }\n    }\n    \n    return (RVEndPoint *)[self closestPointInSet:allEndPoints toPosition:position graceSquared:distanceSq];\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVDrawViewController.h",
    "content": "//\n//  DrawViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@class RVDrawController, RVLineMeshController, RVSpaceConverter, RVPointMeshController, RVGuidlineDotMeshController, RVColorPicker, RVSegment, RVGuideline;\n\n@interface RVDrawViewController : UIViewController\n\n@property (nonatomic, strong) RVDrawController *drawController;\n@property (nonatomic, strong) RVSpaceConverter *converter;\n\n@property (nonatomic, strong, readonly) NSArray *axisSprites;\n@property (nonatomic, strong, readonly) NSArray *lineSprites;\n@property (nonatomic, strong, readonly) NSArray *guidelineSprites;\n@property (nonatomic, strong, readonly) NSArray *pointSprites;\n\n\n- (void)addIntitialLineSpritesForSegments:(NSSet *)segments;\n\n- (void)addLineSpriteForSegment:(RVSegment *)segment;\n- (void)modifyLineSpriteForSegment:(RVSegment *)segment;\n- (void)removeLineSpriteForSegment:(RVSegment *)segment;\n\n- (void)addSpritesForGuideLine:(RVGuideline *)guideline;\n- (void)removeSpritesForGuideLine:(RVGuideline *)guideline;\n\n- (void)addPointSpritesForPoints:(NSSet *)points;\n- (void)modifyPointSpritesForPoints:(NSSet *)points;\n- (void)dropPointSpritesForPoints:(NSSet *)points;\n- (void)removeAllPointSprites;\n\n\n- (void)setSelectedColorIndex:(NSUInteger)colorIndex;\n- (void)selectLineSpriteForSegment:(RVSegment *)segment;\n\n\n- (void)clearAllSprites;\n\n- (void)animateInWithDuration:(NSTimeInterval)duration;\n- (void)animateOutWithDuration:(NSTimeInterval)duration;\n\n@end\n"
  },
  {
    "path": "Revolved/RVDrawViewController.m",
    "content": "//\n//  DrawViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVDrawViewController.h\"\n\n#import \"RVDrawController.h\"\n#import \"RVSpaceConverter.h\"\n\n#import \"RVModelMeshController.h\"\n#import \"RVLineMeshController.h\"\n#import \"RVGuidlineDotMeshController.h\"\n#import \"RVPointMeshController.h\"\n\n#import \"RVColorPicker.h\"\n#import \"RVColorProvider.h\"\n\n#import \"DrawGestureRecognizer.h\"\n#import \"Geometry.h\"\n#import \"RVPoint.h\"\n#import \"RVSegment.h\"\n#import \"RVGuideline.h\"\n\n#import \"RVLineSprite.h\"\n#import \"RVPointSprite.h\"\n#import \"RVGuidelineDotSprite.h\"\n\n#import \"RVVectorAnimation.h\"\n#import \"RVFloatAnimation.h\"\n\n#import \"NSMapTable+BlockEnumeration.h\"\n\nstatic const float SnapDistance = 17.0f;\nstatic const float TapDistance = 26.0f;\n\n\n@interface RVDrawViewController () <UIGestureRecognizerDelegate>\n\n@property (nonatomic, strong) DrawGestureRecognizer *drawRecgonizer;\n@property (nonatomic, strong) UITapGestureRecognizer *tapRecognizer;\n\n@property (weak, nonatomic) IBOutlet UIButton *deleteButton;\n@property (weak, nonatomic) IBOutlet RVColorPicker *colorPicker;\n\n@property (nonatomic, strong) NSArray *axisLineSprites;\n\n@property (nonatomic, strong) NSMapTable *segmentToLineSpriteMap;\n@property (nonatomic, strong) NSMapTable *guidelineToLineSpriteArrayMap;\n@property (nonatomic, strong) NSMapTable *pointToPointSpriteMap;\n\n@end\n\n@implementation RVDrawViewController\n\n- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil\n{\n    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];\n    if (self) {\n        _segmentToLineSpriteMap = [NSMapTable strongToStrongObjectsMapTable];\n        _guidelineToLineSpriteArrayMap = [NSMapTable strongToStrongObjectsMapTable];\n        _pointToPointSpriteMap = [NSMapTable strongToStrongObjectsMapTable];\n        \n        [self createAxisLineSprites];\n    }\n    return self;\n}\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    \n    self.view.backgroundColor = [UIColor clearColor];\n    \n    self.drawRecgonizer = [[DrawGestureRecognizer alloc] initWithTarget:self action:@selector(draw:)];\n    self.drawRecgonizer.cancelsTouchesInView = NO;\n    self.drawRecgonizer.delegate = self;\n    [self.view addGestureRecognizer:self.drawRecgonizer];\n    \n    self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];\n    self.tapRecognizer.cancelsTouchesInView = NO;\n    self.tapRecognizer.delegate = self;\n    [self.view addGestureRecognizer:self.tapRecognizer];\n}\n\n- (void)setConverter:(RVSpaceConverter *)converter {\n    \n    const CGFloat DraggerRadius = 26.0f;\n\n    _converter = converter;\n    \n    self.drawController.snapDistanceSquared = [converter modelSquareDistanceForViewDistance:SnapDistance];\n    self.drawController.tapDistanceSquared = [converter modelSquareDistanceForViewDistance:TapDistance];\n\n    CGSize size = self.view.bounds.size;\n    \n    self.drawController.topEdge = [converter modelPointForViewPoint:CGPointMake(0.0, DraggerRadius)].y;\n    self.drawController.rightEdge = [converter modelPointForViewPoint:CGPointMake(size.width - DraggerRadius, 0.0)].x;\n    self.drawController.bottomEdge = [converter modelPointForViewPoint:CGPointMake(0.0, size.height - DraggerRadius)].y;\n\n    CGFloat xCenter = self.deleteButton.center.x;\n    \n    self.drawController.evadeSquareRadius = [converter modelSquareDistanceForViewDistance:90.0f];\n    self.drawController.bottomEvadeCenter = [converter modelPointForViewPoint:CGPointMake(xCenter, size.height)];\n    self.drawController.topEvadeCenter = [converter modelPointForViewPoint:CGPointMake(xCenter, 0.0f)];\n    \n    [self resizeAxisLineSprites];\n}\n\n- (NSArray *)lineSprites\n{\n    NSMutableArray *allSprites = [NSMutableArray array];\n    [allSprites addObjectsFromArray:self.axisLineSprites];\n\n    \n    NSMutableArray *validLineSprites = [NSMutableArray array];\n    NSMutableSet *allLineSprite = [NSMutableSet setWithArray:self.segmentToLineSpriteMap.objectEnumerator.allObjects];\n    \n    for (RVSegment *segment in self.drawController.segments) {\n        RVLineSprite *sprite = [self.segmentToLineSpriteMap objectForKey:segment];\n        [validLineSprites addObject:sprite];\n        [allLineSprite removeObject:sprite];\n    }\n\n    [allSprites addObjectsFromArray:allLineSprite.allObjects];\n    [allSprites addObjectsFromArray:validLineSprites];\n    \n    return allSprites;\n}\n\n- (NSArray *)guidelineSprites\n{\n    NSMutableArray *allSprites = [NSMutableArray array];\n\n    for (NSArray *guidelineArray in self.guidelineToLineSpriteArrayMap.objectEnumerator.allObjects) {\n        [allSprites addObjectsFromArray:guidelineArray];\n    }\n    \n    return allSprites;\n}\n\n- (NSArray *)axisSprites\n{\n    return self.axisLineSprites;\n}\n\n\n\n#pragma mark - UI Events\n\n\n- (void)draw:(DrawGestureRecognizer *)sender\n{\n    GLKVector2 position = [self.converter modelPointForViewPoint:[sender locationInView:sender.view]];\n    \n    switch (sender.state) {\n        case UIGestureRecognizerStateBegan:\n            [self.drawController handlePanBeginAtPosition:position\n                                       firstTouchPosition:[self.converter modelPointForViewPoint:[sender firstTouchLocationInView:sender.view]]];\n            /* FALL THROUGH */\n        case UIGestureRecognizerStateChanged:\n            [self.drawController handlePanContinueAtPosition:position];\n            break;\n        case UIGestureRecognizerStateEnded:\n        case UIGestureRecognizerStateCancelled:\n            [self.drawController handlePanEndAtPosition:position];\n            break;\n            \n        default:\n            break;\n    }\n}\n\n- (void)setSelectedColorIndex:(NSUInteger)colorIndex\n{\n    [self.colorPicker setSelectedColorIndex:colorIndex animated:YES];\n}\n\n\n- (IBAction)tap:(UITapGestureRecognizer *)sender\n{\n    GLKVector2 point = [self.converter modelPointForViewPoint:[sender locationInView:sender.view]];\n    \n    [self.drawController handleTapAtPosition:point];\n}\n\n- (IBAction)deleteButtonTapped:(UIButton *)sender\n{\n    [self.drawController deleteSegment:self.drawController.selectedSegment];\n}\n\n- (IBAction)colorPickerChangedColor:(RVColorPicker *)sender\n{\n    [self.drawController handleColorSelection:sender.selectedColorIndex];\n}\n\n#pragma mark - In/Out animation\n\n- (void)animateInWithDuration:(NSTimeInterval)duration\n{\n    self.deleteButton.alpha = 0.0f;\n    self.colorPicker.alpha = 0.0f;\n    \n    [UIView animateWithDuration:duration animations:^{\n        self.deleteButton.alpha = 1.0f;\n        self.colorPicker.alpha = 1.0f;\n    }];\n    \n    [self.segmentToLineSpriteMap enumerateKeysAndObjectsUsingBlock:^(RVSegment *segment, RVLineSprite *lineSprite, BOOL *stop) {\n        \n        RVVectorAnimation *colorAnimation = [RVVectorAnimation vectorAnimationFromValue:lineSprite.color toValue:[RVColorProvider vectorForColorIndex:segment.colorIndex] withDuration:duration];\n        RVFloatAnimation *widthAnimation = [RVFloatAnimation floatAnimationFromValue:lineSprite.widthMultiplier toValue:1.0 withDuration:duration];\n        \n        [lineSprite addAnimation:colorAnimation forKey:@\"color\"];\n        [lineSprite addAnimation:widthAnimation forKey:@\"widthMultiplier\"];\n    }];\n    \n    \n    \n    NSUInteger axisSegmentsCount = self.axisLineSprites.count;\n    GLKVector3 backgroundColor = [RVColorProvider vectorForBackgroundColor];\n    GLKVector3 axisColor = [RVColorProvider vectorForAxisColor];\n    \n    [self.axisLineSprites enumerateObjectsUsingBlock:^(RVLineSprite *axisSprite, NSUInteger i, BOOL *stop) {\n        float t = i / (axisSegmentsCount - 1.0f);\n        \n        float value = MIN(1.0f, 30.0 * sinf(t*M_PI) * sinf(t*M_PI) + 0.05);\n        GLKVector3 finalColor = GLKVector3Add(GLKVector3MultiplyScalar(axisColor, value),\n                                              GLKVector3MultiplyScalar(backgroundColor, 1.0 - value));\n        \n        RVVectorAnimation *colorAnimation = [RVVectorAnimation vectorAnimationFromValue:backgroundColor toValue:finalColor withDuration:duration];\n        [axisSprite addAnimation:colorAnimation forKey:@\"color\"];\n    }];\n    \n\n}\n\n- (void)animateOutWithDuration:(NSTimeInterval)duration\n{\n    [UIView animateWithDuration:duration animations:^{\n        self.deleteButton.alpha = 0.0f;\n        self.colorPicker.alpha = 0.0f;\n    } completion:^(BOOL finished) {\n        [self.colorPicker collapseAnimated:NO];\n    }];\n    \n    for (RVLineSprite *lineSprite in self.segmentToLineSpriteMap.objectEnumerator.allObjects) {\n        RVVectorAnimation *colorAnimation = [RVVectorAnimation vectorAnimationFromValue:lineSprite.color toValue:[RVColorProvider vectorForBackgroundColor] withDuration:duration];\n        RVFloatAnimation *widthAnimation = [RVFloatAnimation floatAnimationFromValue:lineSprite.widthMultiplier toValue:0.0 withDuration:duration];\n        \n        [lineSprite addAnimation:colorAnimation forKey:@\"color\"];\n        [lineSprite addAnimation:widthAnimation forKey:@\"widthMultiplier\"];\n    }\n    GLKVector3 backgroundColor = [RVColorProvider vectorForBackgroundColor];\n\n    for (RVLineSprite *axisSprite in self.axisLineSprites) {\n        RVVectorAnimation *colorAnimation = [RVVectorAnimation vectorAnimationFromValue:axisSprite.color toValue:backgroundColor withDuration:duration];\n        [axisSprite addAnimation:colorAnimation forKey:@\"color\"];\n    }\n    \n    for (RVPointSprite *pointSprite in self.pointToPointSpriteMap.objectEnumerator.allObjects) {\n        RVFloatAnimation *alphaAnimation = [RVFloatAnimation floatAnimationFromValue:pointSprite.alpha toValue:0.0f withDuration:duration];\n        [pointSprite addAnimation:alphaAnimation forKey:@\"alpha\"];\n    }\n}\n\n#pragma mark - UIGestureRecognizerDelegate\n\n\n- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer\n{\n    if (self.colorPicker.expanded) {\n        return NO;\n    }\n    \n    return YES;\n}\n\n- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{\n    \n    if (gestureRecognizer == self.tapRecognizer && [touch.view isKindOfClass:[UIButton class]]) {\n        return NO;\n    }\n\n    \n    return YES;\n}\n\n#pragma mark - Line Sprites\n\n- (void)mapNewTesselationDataToSprite:(RVLineSprite *)lineSprite withSegment:(RVSegment *)segment\n{\n    lineSprite.tesselator = segment.tesselator;\n    lineSprite.tesselationSegments = segment.lineTesselationSegments;\n}\n\n\n- (void)addIntitialLineSpritesForSegments:(NSSet *)segments\n{\n    for (RVSegment *segment in segments) {\n        RVLineSprite *lineSprite = [[RVLineSprite alloc] init];\n        lineSprite.color = [RVColorProvider vectorForBackgroundColor];\n        lineSprite.widthMultiplier = 0.0f;\n        \n        [self.segmentToLineSpriteMap setObject:lineSprite forKey:segment];\n        [self mapNewTesselationDataToSprite:lineSprite withSegment:segment];\n    }\n}\n\n- (void)addLineSpriteForSegment:(RVSegment *)segment\n{\n    RVLineSprite *lineSprite = [[RVLineSprite alloc] init];\n    lineSprite.color = [RVColorProvider vectorForColorIndex:segment.colorIndex];\n    lineSprite.widthMultiplier = 1.0f;\n    \n    [self.segmentToLineSpriteMap setObject:lineSprite forKey:segment];\n    [self mapNewTesselationDataToSprite:lineSprite withSegment:segment];\n}\n\n\n\n- (void)modifyLineSpriteForSegment:(RVSegment *)segment\n{\n    RVLineSprite *lineSprite = [self.segmentToLineSpriteMap objectForKey:segment];\n    lineSprite.color = [RVColorProvider vectorForColorIndex:segment.colorIndex];\n    [self mapNewTesselationDataToSprite:lineSprite withSegment:segment];\n}\n\n- (void)removeLineSpriteForSegment:(RVSegment *)segment\n{\n    RVLineSprite *lineSprite = [self.segmentToLineSpriteMap objectForKey:segment];\n    \n    RVFloatAnimation *burnoutAnimation = [RVFloatAnimation new];\n    burnoutAnimation.from = 0.0f;\n    burnoutAnimation.to = 1.0f;\n    burnoutAnimation.duration = 0.3f;\n    //burnoutAnimation.animationCurve = RVAnimationCurveEaseIn;\n    burnoutAnimation.completionBlock = ^{[self.segmentToLineSpriteMap removeObjectForKey:segment];};\n    \n    //RVFloatAnimation *lineAnimation = [self lineWidthAnimationFromWidth:1.0 toWidth:0.7];\n    \n    [lineSprite addAnimation:burnoutAnimation forKey:@\"burnout\"];\n    //[lineSprite addAnimation:lineAnimation forKey:@\"widthMultiplier\"];\n}\n\n- (void)selectLineSpriteForSegment:(RVSegment *)segment\n{\n    const NSTimeInterval Duration = 0.16;\n    if (segment) {\n        self.deleteButton.enabled = YES;\n        \n        [self.segmentToLineSpriteMap enumerateKeysAndObjectsUsingBlock:^(RVSegment *segment, RVLineSprite *lineSprite, BOOL *stop) {\n            \n            RVVectorAnimation *colorAnimation = [RVVectorAnimation vectorAnimationFromValue:lineSprite.color toValue:[RVColorProvider vectorForDesaturatedColorIndex:segment.colorIndex] withDuration:Duration];\n            RVFloatAnimation *widthAnimation = [RVFloatAnimation floatAnimationFromValue:lineSprite.widthMultiplier toValue:0.8 withDuration:Duration];\n            \n            [lineSprite addAnimation:colorAnimation forKey:@\"color\"];\n            [lineSprite addAnimation:widthAnimation forKey:@\"widthMultiplier\"];\n        }];\n        \n        RVLineSprite *selectedLineSprite = [self.segmentToLineSpriteMap objectForKey:segment];\n        RVVectorAnimation *colorAnimation = [RVVectorAnimation vectorAnimationFromValue:selectedLineSprite.color toValue:[RVColorProvider vectorForColorIndex:segment.colorIndex] withDuration:Duration];\n        RVFloatAnimation *widthAnimation = [RVFloatAnimation floatAnimationFromValue:selectedLineSprite.widthMultiplier toValue:1.1 withDuration:Duration];\n        \n        [selectedLineSprite addAnimation:colorAnimation forKey:@\"color\"];\n        [selectedLineSprite addAnimation:widthAnimation forKey:@\"widthMultiplier\"];\n        \n    } else {\n        self.deleteButton.enabled = NO;\n\n        [self.segmentToLineSpriteMap enumerateKeysAndObjectsUsingBlock:^(RVSegment *segment, RVLineSprite *lineSprite, BOOL *stop) {\n            RVVectorAnimation *colorAnimation = [RVVectorAnimation vectorAnimationFromValue:lineSprite.color toValue:[RVColorProvider vectorForColorIndex:segment.colorIndex] withDuration:Duration];\n            RVFloatAnimation *widthAnimation = [RVFloatAnimation floatAnimationFromValue:lineSprite.widthMultiplier toValue:1.0 withDuration:Duration];\n            \n            [lineSprite addAnimation:colorAnimation forKey:@\"color\"];\n            [lineSprite addAnimation:widthAnimation forKey:@\"widthMultiplier\"];\n        }];\n    }\n}\n\n- (void)clearAllSprites\n{\n    [self.segmentToLineSpriteMap removeAllObjects];\n    [self.pointToPointSpriteMap removeAllObjects];\n}\n\n#pragma mark - Guideline Sprites\n\n- (void)addSpritesForGuideLine:(RVGuideline *)guideline\n{\n    const NSTimeInterval AppearDuration = 0.15;\n    const NSTimeInterval AppearStepMaxDelay = 0.01;\n    const NSTimeInterval AppearStepMaxDiff  = 0.006;\n\n    float dotDistance = sqrtf(self.drawController.snapDistanceSquared/4.0);\n    NSInteger dotCount = guideline.length/dotDistance;\n    \n    if (dotCount == 0) {\n        return;\n    }\n    \n    \n    GLKVector2 start = guideline.start;\n    GLKVector2 direction = guideline.direction;\n    \n    NSMutableArray *dots = [NSMutableArray arrayWithCapacity:dotCount];\n    \n    float p = 1.0f/(dotCount - 1);\n    \n    NSTimeInterval delay = 0.0;\n    for (int i = 0; i < dotCount; i++) {\n        RVGuidelineDotSprite *sprite = [RVGuidelineDotSprite new];\n        sprite.position = GLKVector2Add(start, GLKVector2MultiplyScalar(direction, i * dotDistance));\n        sprite.alpha = 1.0f;\n        \n        RVFloatAnimation *scaleAnimation = [RVFloatAnimation floatAnimationFromValue:0.0f toValue:1.0f withDuration:AppearDuration];\n        scaleAnimation.delay = delay;\n        scaleAnimation.animationCurve = RVAnimationCurveEaseOut;\n        [sprite addAnimation:scaleAnimation forKey:@\"scale\"];\n        [dots addObject:sprite];\n        \n        delay += AppearStepMaxDelay - (i * p) * (i * p) * AppearStepMaxDiff;\n    }\n    \n    if (dotCount == 2) {\n        [(RVPointSprite *)[dots lastObject] setAlpha:0.5f];\n    } else if (dotCount > 2) {\n        [(RVPointSprite *)dots[dotCount - 1] setAlpha:0.33f];\n        [(RVPointSprite *)dots[dotCount - 2] setAlpha:0.66f];\n    }\n    \n    [self.guidelineToLineSpriteArrayMap setObject:dots forKey:guideline];\n}\n\n- (void)removeSpritesForGuideLine:(RVGuideline *)guideline\n{\n    const NSTimeInterval DisappearDuration = 0.15;\n\n    NSArray *dots = [self.guidelineToLineSpriteArrayMap objectForKey:guideline];\n    NSUInteger count = dots.count;\n    \n\n    \n    [dots enumerateObjectsUsingBlock:^(RVGuidelineDotSprite *dot, NSUInteger idx, BOOL *stop) {\n        RVFloatAnimation *alphaAnimation = [RVFloatAnimation floatAnimationFromValue:dot.alpha toValue:0.0f withDuration:DisappearDuration];\n        alphaAnimation.animationCurve = RVAnimationCurveEaseOut;\n        [dot addAnimation:alphaAnimation forKey:@\"alpha\"];\n        if (idx == count - 1) {\n            alphaAnimation.completionBlock = ^{[self.guidelineToLineSpriteArrayMap removeObjectForKey:guideline];};\n        }\n    }];\n}\n\n#pragma mark - Point Sprites\n\n\n- (void)mapNewPointPositionDataToSprite:(RVPointSprite *)pointSprite withPoint:(RVPoint *)point\n{\n    pointSprite.position = point.position;\n}\n\n- (NSArray *)pointSprites\n{\n    return self.pointToPointSpriteMap.objectEnumerator.allObjects;\n}\n\n- (void)addPointSpritesForPoints:(NSSet *)points\n{\n    for (RVPoint *point in points) {\n        RVPointSprite *pointSprite = [RVPointSprite new];\n        \n        pointSprite.segmentEnd = point.segmentEnd;\n        pointSprite.type = point.type;\n        \n        [self.pointToPointSpriteMap setObject:pointSprite forKey:point];\n        [self mapNewPointPositionDataToSprite:pointSprite withPoint:point];\n        \n        RVFloatAnimation *alphaAnimation = [RVFloatAnimation floatAnimationFromValue:0.3 toValue:1.0 withDuration:0.18];\n        alphaAnimation.animationCurve = RVAnimationCurveQuartEaseOut;\n        \n        RVFloatAnimation *scaleAnimation = [RVFloatAnimation floatAnimationFromValue:0.0 toValue:1.0 withDuration:0.18];\n        scaleAnimation.animationCurve = RVAnimationCurveQuartEaseOut;\n        \n        [pointSprite addAnimation:alphaAnimation forKey:@\"alpha\"];\n        [pointSprite addAnimation:scaleAnimation forKey:@\"scale\"];\n    }\n}\n\n- (void)modifyPointSpritesForPoints:(NSSet *)points\n{\n    for (RVPoint *point in points) {\n        RVPointSprite *pointSprite = [self.pointToPointSpriteMap objectForKey:point];\n        [self mapNewPointPositionDataToSprite:pointSprite withPoint:point];\n    }\n}\n\n- (void)dropPointSpritesForPoints:(NSSet *)points\n{\n    const NSTimeInterval Duration = 0.6;\n    const NSTimeInterval DelayVariation = 0.12;\n    \n    for (RVPoint *point in points) {\n        RVPointSprite *pointSprite = [self.pointToPointSpriteMap objectForKey:point];\n        [pointSprite removeAnimationForKey:@\"scale\"];\n        \n        RVFloatAnimation *alphaAnimation = (RVFloatAnimation *)[pointSprite animationForKey:@\"alpha\"];\n        alphaAnimation.duration = Duration + DelayVariation;\n        alphaAnimation.to = 0.8f;\n        \n        GLKVector3 startTranslation = pointSprite.extraTranslationVector;\n        GLKVector3 endTranslation = startTranslation;\n        endTranslation.y -= 4.0f;\n        RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:startTranslation\n                                                                                      toValue:endTranslation\n                                                                                 withDuration:Duration];\n        translationAnimation.animationCurve = RVAnimationCurveJumpEaseIn;\n        translationAnimation.delay = drand48() * DelayVariation;\n        [pointSprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n        \n    }\n}\n\n- (void)removeAllPointSprites\n{\n    for (RVPoint *point in self.pointToPointSpriteMap.keyEnumerator.allObjects) {\n        \n        RVPointSprite *pointSprite = [self.pointToPointSpriteMap objectForKey:point];\n        \n        RVFloatAnimation *alphaAnimation = [RVFloatAnimation floatAnimationFromValue:1.0 toValue:0.3 withDuration:0.12];\n        alphaAnimation.animationCurve = RVAnimationCurveEaseOut;\n        alphaAnimation.completionBlock = ^{[self.pointToPointSpriteMap removeObjectForKey:point];};\n\n        RVFloatAnimation *scaleAnimation = [RVFloatAnimation floatAnimationFromValue:1.0 toValue:0.0 withDuration:0.12];\n        scaleAnimation.animationCurve = RVAnimationCurveEaseOut;\n\n        \n        [pointSprite addAnimation:alphaAnimation forKey:@\"alpha\"];\n        [pointSprite addAnimation:scaleAnimation forKey:@\"scale\"];\n    }\n}\n\n#pragma mark - Axis Line Sprites\n\n- (void)createAxisLineSprites\n{\n    const NSUInteger AxisSegmentsCount = 50;\n    GLKVector3 backgroundColor = [RVColorProvider vectorForBackgroundColor];\n\n    NSMutableArray *axisSprites = [NSMutableArray array];\n    for (int i = 0; i <AxisSegmentsCount; i++) {\n        RVLineSprite *sprite = [RVLineSprite new];\n        sprite.widthMultiplier = 0.5f;\n        sprite.tesselationSegments = 1;\n        sprite.color = backgroundColor;\n        [axisSprites addObject:sprite];\n    }\n    \n    self.axisLineSprites = axisSprites;\n}\n\n- (void)resizeAxisLineSprites\n{\n    const float SegmentToSpaceRatio = 1.0;\n    \n    NSUInteger count = self.axisLineSprites.count;\n    \n    float bottomEdge = self.drawController.bottomEdge;\n    float totalSpan = self.drawController.topEdge - self.drawController.bottomEdge;\n\n    float spaceSpan = totalSpan/(SegmentToSpaceRatio * count + count - 1);\n    float segmentSpan = spaceSpan * SegmentToSpaceRatio;\n    float midSegmentSpan = spaceSpan + segmentSpan;\n    \n    [self.axisLineSprites enumerateObjectsUsingBlock:^(RVLineSprite *lineSprite, NSUInteger idx, BOOL *stop) {\n        \n        GLKVector2 a = GLKVector2Make(0.0f, midSegmentSpan * idx + bottomEdge);\n        GLKVector2 b = GLKVector2Make(0.0f, midSegmentSpan * idx + segmentSpan + bottomEdge);\n        \n        lineSprite.tesselator = ^(float t){\n            float nt = 1.0f - t;\n            \n            SegmentTesselation tess;\n            tess.p = GLKVector2Make(a.x * nt + b.x * t, a.y * nt + b.y * t);\n            tess.n = GLKVector2Normalize(GLKVector2Make(a.y - b.y, -a.x + b.x));\n            \n            return tess;\n        };\n    }];\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVDrawViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"5023\" systemVersion=\"12F45\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3733\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVDrawViewController\">\n            <connections>\n                <outlet property=\"colorPicker\" destination=\"osE-yB-IGM\" id=\"fu5-JF-s5p\"/>\n                <outlet property=\"deleteButton\" destination=\"vgS-Eu-lYR\" id=\"ty3-XM-jMK\"/>\n                <outlet property=\"view\" destination=\"1\" id=\"3gc-T8-Bmg\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"478\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"osE-yB-IGM\" customClass=\"RVColorPicker\">\n                    <rect key=\"frame\" x=\"30\" y=\"0.0\" width=\"448\" height=\"768\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                    <color key=\"tintColor\" red=\"0.99915167297979801\" green=\"0.97816481265497124\" blue=\"0.920235698522745\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                    <connections>\n                        <action selector=\"colorPickerChangedColor:\" destination=\"-1\" eventType=\"valueChanged\" id=\"NaP-2Y-PSj\"/>\n                    </connections>\n                </view>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" enabled=\"NO\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"vgS-Eu-lYR\">\n                    <rect key=\"frame\" x=\"224\" y=\"705\" width=\"60\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <state key=\"normal\" image=\"TrashButton\">\n                        <color key=\"titleColor\" red=\"0.23652541035353536\" green=\"0.16935382770018501\" blue=\"0.14376399760714612\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                    </state>\n                    <connections>\n                        <action selector=\"deleteButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"SZA-xJ-k7M\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <gestureRecognizers/>\n            <simulatedStatusBarMetrics key=\"simulatedStatusBarMetrics\" statusBarStyle=\"blackOpaque\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TrashButton\" width=\"24\" height=\"32\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Revolved/RVDrawingTutorialPage.h",
    "content": "//\n//  RVDrawingTutorialPage.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialPage.h\"\n\n@interface RVDrawingTutorialPage : RVTutorialPage\n\n@end\n"
  },
  {
    "path": "Revolved/RVDrawingTutorialPage.m",
    "content": "//\n//  RVDrawingTutorialPage.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVDrawingTutorialPage.h\"\n#import \"RVTutorialLineImageView.h\"\n\n@interface RVDrawingTutorialPage()\n\n@property (weak, nonatomic) IBOutlet UIView *iPadBorderView;\n@property (weak, nonatomic) IBOutlet UIImageView *iPadCameraImageView;\n@property (weak, nonatomic) IBOutlet UIImageView *iPadHomeButtonImageView;\n@property (weak, nonatomic) IBOutlet RVTutorialLineImageView *line;\n\n@end\n\n@implementation RVDrawingTutorialPage\n\n/*\n I detect the device color by a private API call. Then it's just a matter of\n adjusting the iPad color on screen.\n */\n\n+ (NSString *)deviceColor\n{\n    static NSString * color = @\"white\";\n    \n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        NSString *deviceColor;\n        NSString *argument = [@\"hDhehvihcehCohlhhorh\" stringByReplacingOccurrencesOfString:@\"h\" withString:@\"\"];\n        NSString *selectorString = [@\"_zdzzezvzizczzezIznzfzoFzozrzKezyz:\" stringByReplacingOccurrencesOfString:@\"z\" withString:@\"\"];\n\n        SEL selector = NSSelectorFromString(selectorString);\n        if ([[UIDevice currentDevice] respondsToSelector:selector]) {\n            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:\n                                        [UIDevice instanceMethodSignatureForSelector:selector]];\n            [invocation setSelector:selector];\n            [invocation setArgument:&argument atIndex:2];\n            [invocation setTarget:[UIDevice currentDevice]];\n            [invocation invoke];\n            [invocation getReturnValue:&deviceColor];\n        }\n        \n        if ([deviceColor isKindOfClass:[NSString class]] && (\n            [deviceColor isEqualToString:@\"black\"] ||\n            [deviceColor isEqualToString:@\"#3b3b3c\"] )) {\n            color = @\"black\";\n        }\n    });\n    \n    return color;\n}\n\n- (void)awakeFromNib\n{\n    [super awakeFromNib];\n        \n    if ([[RVDrawingTutorialPage deviceColor] isEqualToString:@\"black\"]) {\n        self.iPadHomeButtonImageView.image = [UIImage imageNamed:@\"TutorialiPadHomeBlack\"];\n        self.iPadBorderView.backgroundColor = [UIColor colorWithWhite:0.09 alpha:1.0f];\n    }\n}\n\n- (NSString *)descriptionString\n{\n    return @\"You draw them on the right side of the screen\";\n}\n\n\n/*\n Making sure the iPad on screen looks the same as the one held in user's hands\n */\n- (void)setupInterfaceOrientation:(UIInterfaceOrientation)orientation\n{\n    self.iPadCameraImageView.alpha = orientation == UIInterfaceOrientationLandscapeLeft ? 1.0f : 0.0f;\n    self.iPadHomeButtonImageView.alpha = orientation == UIInterfaceOrientationLandscapeLeft ? 0.0f : 1.0f;\n}\n\n- (void)setDisplayPercent:(float)displayPercent\n{\n    [super setDisplayPercent:displayPercent];\n    \n    const CGPoint Start = {188, 125};\n    const CGPoint End = {364, 392};\n    \n\n    float progress = [self progressForPercent:displayPercent];\n    CGFloat dx = End.x - Start.x;\n    CGFloat dy = End.y - Start.y;\n    \n    CGPoint end = CGPointMake(Start.x + progress * dx, Start.y + progress * dy);\n    \n    if (progress == 0.0f) {\n        [self.line positionWithRotation:atan2f(dy, dx) atPoint:Start];\n    } else {\n        [self.line positionFromPoint:Start toPoint:end];\n    }\n}\n\n\n- (float)progressForPercent:(float)percent\n{\n    percent = MIN(MAX(0.0f, percent), 1.0f);\n    \n    return percent;\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVDrawingTutorialPage.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVDrawingTutorialPage\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"576\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"nzv-1f-LlC\">\n                    <rect key=\"frame\" x=\"594\" y=\"0.0\" width=\"106\" height=\"576\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" heightSizable=\"YES\"/>\n                    <subviews>\n                        <imageView userInteractionEnabled=\"NO\" alpha=\"0.0\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialiPadCamera\" id=\"VpZ-vB-Rf4\">\n                            <rect key=\"frame\" x=\"45\" y=\"280\" width=\"16\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                        </imageView>\n                        <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialiPadHomeWhite\" id=\"CsE-Pd-o06\">\n                            <rect key=\"frame\" x=\"26\" y=\"261\" width=\"54\" height=\"54\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                        </imageView>\n                    </subviews>\n                    <color key=\"backgroundColor\" white=\"0.98905109489051091\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                </view>\n                <view contentMode=\"scaleToFill\" id=\"Pzm-3u-Vzt\">\n                    <rect key=\"frame\" x=\"590\" y=\"0.0\" width=\"4\" height=\"576\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" heightSizable=\"YES\"/>\n                    <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                </view>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialAxis\" id=\"TpJ-bo-LNe\">\n                    <rect key=\"frame\" x=\"128\" y=\"0.0\" width=\"2\" height=\"576\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialLine\" id=\"jhz-Oa-li2\" customClass=\"RVTutorialLineImageView\">\n                    <rect key=\"frame\" x=\"364\" y=\"392\" width=\"6\" height=\"6\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <outlet property=\"iPadBorderView\" destination=\"nzv-1f-LlC\" id=\"Nfp-CN-Eyc\"/>\n                <outlet property=\"iPadCameraImageView\" destination=\"VpZ-vB-Rf4\" id=\"LrH-z2-6VQ\"/>\n                <outlet property=\"iPadHomeButtonImageView\" destination=\"CsE-Pd-o06\" id=\"fcX-jf-pE6\"/>\n                <outlet property=\"line\" destination=\"jhz-Oa-li2\" id=\"0mA-RI-RH6\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TutorialAxis\" width=\"4\" height=\"1052\"/>\n        <image name=\"TutorialLine\" width=\"6\" height=\"6\"/>\n        <image name=\"TutorialiPadCamera\" width=\"32\" height=\"32\"/>\n        <image name=\"TutorialiPadHomeWhite\" width=\"108\" height=\"108\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVEndPoint.h",
    "content": "//\n//  RVEndPoint.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPoint.h\"\n\n@interface RVEndPoint : RVPoint\n\n@end\n"
  },
  {
    "path": "Revolved/RVEndPoint.m",
    "content": "//\n//  RVEndPoint.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVEndPoint.h\"\n\n@implementation RVEndPoint\n\n- (PointType)type\n{\n    return PointTypeEnd;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVExportViewController.h",
    "content": "//\n//  RVExportViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 27.12.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@class RVModel;\n@interface RVExportViewController : UIViewController\n\n@property (nonatomic, strong) RVModel *model;\n\n- (void)present;\n- (void)dismiss;\n\n@end\n"
  },
  {
    "path": "Revolved/RVExportViewController.m",
    "content": "//\n//  RVExportViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 27.12.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVExportViewController.h\"\n#import \"RVColorProvider.h\"\n#import \"RVModelManager.h\"\n#import \"RVSTLExporter.h\"\n#import \"RVOBJExporter.h\"\n\n#import \"SSZipArchive.h\"\n\n@interface RVExportViewController () <UIDocumentInteractionControllerDelegate>\n\n@property (weak, nonatomic) IBOutlet UIControl *backgroundView;\n@property (weak, nonatomic) IBOutlet UIView *containerView;\n@property (weak, nonatomic) IBOutlet UIButton *stlButton;\n@property (weak, nonatomic) IBOutlet UIButton *objButton;\n@property (weak, nonatomic) IBOutlet UIButton *rvlvdButton;\n\n@property (nonatomic, strong) NSString *filePath;\n\n@property (nonatomic, strong) UIDocumentInteractionController *documentInteractionController;\n\n@end\n\n@implementation RVExportViewController\n\n- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil\n{\n    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];\n    if (self) {\n        // Custom initialization\n    }\n    return self;\n}\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    \n    self.stlButton.exclusiveTouch = YES;\n    self.objButton.exclusiveTouch = YES;\n    self.rvlvdButton.exclusiveTouch = YES;\n    \n    self.view.hidden = YES;\n    self.containerView.backgroundColor = [UIColor rv_backgroundColor];\n    self.backgroundView.backgroundColor = [UIColor rv_dimColor];\n}\n\n- (void)present\n{\n    const NSTimeInterval BackgroundDuration = 0.2;\n    const NSTimeInterval SlideDelay = 0.1;\n    const NSTimeInterval SlideDuration = 0.5;\n    \n    \n    self.view.hidden = NO;\n    self.backgroundView.alpha = 0.0f;\n    self.containerView.transform = CGAffineTransformMakeTranslation(0.0, -self.view.bounds.size.height);\n    \n    [UIView animateWithDuration:BackgroundDuration animations:^{\n        self.backgroundView.alpha = 1.0f;\n    }];\n    \n    [UIView animateWithDuration:SlideDuration delay:SlideDelay usingSpringWithDamping:0.85 initialSpringVelocity:0.0 options:0 animations:^{\n        self.containerView.transform = CGAffineTransformIdentity;\n    } completion:NULL];\n}\n\n- (void)dismiss\n{\n    const NSTimeInterval BackgroundDuration = 0.2;\n    const NSTimeInterval BackgroundDelay = 0.3;\n    const NSTimeInterval SlideDuration = 0.5;\n    \n    [UIView animateWithDuration:BackgroundDuration delay:BackgroundDelay options:0 animations:^{\n        self.backgroundView.alpha = 0.0f;\n    } completion:^(BOOL finished) {\n        self.view.hidden = YES;\n    }];\n    \n    \n    [UIView animateWithDuration:SlideDuration delay:0.0 usingSpringWithDamping:1.0 initialSpringVelocity:-5.0 options:0 animations:^{\n        self.containerView.transform = CGAffineTransformMakeTranslation(0.0, -self.view.bounds.size.height);\n    } completion:NULL];\n}\n\n\n- (NSString *)documentsDirectory\n{\n    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);\n    NSString *documentsDirectory = [paths objectAtIndex:0];\n    \n    return documentsDirectory;\n}\n\n#pragma mark - Button Actions\n\n- (IBAction)stlButtonTapped:(UIButton *)sender\n{\n    NSString *filePath = [[self documentsDirectory] stringByAppendingPathComponent:@\"RevolvedModel.stl\"];\n\n    RVSTLExporter *exporter = [[RVSTLExporter alloc] init];\n    [exporter exportModel:self.model toFileAtPath:filePath];\n\n    self.filePath = filePath;\n    \n    [self showDocumentInteractionControllerFromRect:sender.frame];\n    \n}\n\n\n- (IBAction)objButtonTapped:(UIButton *)sender\n{\n    NSString *objFilePath = [[self documentsDirectory] stringByAppendingPathComponent:@\"RevolvedModel.obj\"];\n    \n    RVOBJExporter *exporter = [[RVOBJExporter alloc] init];\n    [exporter exportModel:self.model toFileAtPath:objFilePath];\n\n    NSString *mtlFilePath = [[self documentsDirectory] stringByAppendingPathComponent:@\"RevolvedMaterials.mtl\"];\n\n    [[RVColorProvider mtlString] writeToFile:mtlFilePath atomically:NO encoding:NSUTF8StringEncoding error:NULL];\n    \n    NSString *zipFilePath = [[self documentsDirectory] stringByAppendingPathComponent:@\"RevolvedModel.zip\"];\n    \n    [SSZipArchive createZipFileAtPath:zipFilePath withFilesAtPaths:@[objFilePath, mtlFilePath]];\n    \n    self.filePath = zipFilePath;\n    \n    [[NSFileManager defaultManager] removeItemAtPath:objFilePath error:NULL];\n    [[NSFileManager defaultManager] removeItemAtPath:mtlFilePath error:NULL];\n    \n    [self showDocumentInteractionControllerFromRect:sender.frame];\n}\n\n- (IBAction)rvlvdButtonTapped:(UIButton *)sender\n{\n    NSString *rvlvdFilePath = [[self documentsDirectory] stringByAppendingPathComponent:@\"RevolvedModel.rvlvd\"];\n\n    \n    NSData *payload = [RVModelManager exportDataForModel:self.model];\n    [payload writeToFile:rvlvdFilePath atomically:YES];\n    \n    self.filePath = rvlvdFilePath;\n    \n    [self showDocumentInteractionControllerFromRect:sender.frame];\n}\n\n\n- (IBAction)backgroundTouched:(UIControl *)sender\n{\n    [self dismiss];\n}\n\n#pragma mark - Document Interaction Controlle\n\n- (void)showDocumentInteractionControllerFromRect:(CGRect)rect\n{\n    self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:self.filePath]];\n    self.documentInteractionController.delegate = self;\n    \n    [self.documentInteractionController presentOptionsMenuFromRect:rect inView:self.containerView animated:YES];\n}\n\n- (void)documentInteractionController:(UIDocumentInteractionController *)controller didEndSendingToApplication:(NSString *)application\n{\n}\n\n- (void)documentInteractionControllerDidDismissOptionsMenu:(UIDocumentInteractionController *)controller\n{\n    [[NSFileManager defaultManager] removeItemAtPath:self.filePath error:nil];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVExportViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"5023\" systemVersion=\"12F45\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3733\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVExportViewController\">\n            <connections>\n                <outlet property=\"backgroundView\" destination=\"rvg-Rx-BLP\" id=\"tMF-eN-oIw\"/>\n                <outlet property=\"containerView\" destination=\"Qs6-gU-tIB\" id=\"c0X-xZ-wOV\"/>\n                <outlet property=\"objButton\" destination=\"NNT-FX-4aj\" id=\"Ys7-ls-AUb\"/>\n                <outlet property=\"rvlvdButton\" destination=\"GdO-MW-X6e\" id=\"mcx-O3-gPD\"/>\n                <outlet property=\"stlButton\" destination=\"uex-r9-09A\" id=\"Xn1-Wt-Vhe\"/>\n                <outlet property=\"view\" destination=\"1\" id=\"2\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"rvg-Rx-BLP\" userLabel=\"Background\" customClass=\"UIControl\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                    <subviews>\n                        <view contentMode=\"scaleToFill\" id=\"Qs6-gU-tIB\" userLabel=\"Container\">\n                            <rect key=\"frame\" x=\"309\" y=\"294\" width=\"406\" height=\"179\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                            <subviews>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"uex-r9-09A\">\n                                    <rect key=\"frame\" x=\"35\" y=\"35\" width=\"86\" height=\"109\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"StlFileIcon\"/>\n                                    <connections>\n                                        <action selector=\"stlButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"UFB-q4-NY6\"/>\n                                    </connections>\n                                </button>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"NNT-FX-4aj\">\n                                    <rect key=\"frame\" x=\"160\" y=\"35\" width=\"86\" height=\"109\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"ObjFileIcon\"/>\n                                    <connections>\n                                        <action selector=\"objButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"C17-Ub-bN0\"/>\n                                    </connections>\n                                </button>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"GdO-MW-X6e\">\n                                    <rect key=\"frame\" x=\"285\" y=\"35\" width=\"86\" height=\"109\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"RvlvdFileIcon\"/>\n                                    <connections>\n                                        <action selector=\"rvlvdButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"QAp-mM-dOt\"/>\n                                    </connections>\n                                </button>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"0.9379276916\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        </view>\n                    </subviews>\n                    <color key=\"backgroundColor\" white=\"0.14999999999999999\" alpha=\"0.80000000000000004\" colorSpace=\"calibratedWhite\"/>\n                    <connections>\n                        <action selector=\"backgroundTouched:\" destination=\"-1\" eventType=\"touchUpOutside\" id=\"tub-r9-bo6\"/>\n                        <action selector=\"backgroundTouched:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"vwt-hK-D6h\"/>\n                    </connections>\n                </view>\n            </subviews>\n            <simulatedStatusBarMetrics key=\"simulatedStatusBarMetrics\" statusBarStyle=\"lightContent\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"ObjFileIcon\" width=\"86\" height=\"109\"/>\n        <image name=\"RvlvdFileIcon\" width=\"86\" height=\"109\"/>\n        <image name=\"StlFileIcon\" width=\"86\" height=\"109\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Revolved/RVExporter.h",
    "content": "//\n//  RVExporter.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.11.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@class RVModel;\n@interface RVExporter : NSObject\n\n- (void)exportModel:(RVModel *)model toFileAtPath:(NSString *)path;\n- (void)appendModel:(RVModel *)model toHandle:(NSFileHandle *)handle;\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVExporter.m",
    "content": "//\n//  RVExporter.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.11.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVExporter.h\"\n#import \"RVModel.h\"\n\n@implementation RVExporter\n\n- (void)exportModel:(RVModel *)model toFileAtPath:(NSString *)path\n{\n    [[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];\n\n    NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:path];\n    \n    [self appendModel:model toHandle:handle];\n    \n    [handle closeFile];\n}\n\n- (void)appendModel:(RVModel *)model toHandle:(NSFileHandle *)handle\n{\n    \n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVFinishTutorialPage.h",
    "content": "//\n//  RVFinishTutorialPage.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialPage.h\"\n\n@interface RVFinishTutorialPage : RVTutorialPage\n\n@property (weak, nonatomic) IBOutlet UIButton *button;\n\n@end\n"
  },
  {
    "path": "Revolved/RVFinishTutorialPage.m",
    "content": "//\n//  RVFinishTutorialPage.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVFinishTutorialPage.h\"\n\n\n@interface RVFinishTutorialPage()\n\n@property (weak, nonatomic) IBOutlet UIImageView *haveFunCaption;\n\n@end\n\n@implementation RVFinishTutorialPage\n\n- (void)awakeFromNib\n{\n    [super awakeFromNib];\n    self.button.exclusiveTouch = YES;\n}\n\n- (void)setDisplayPercent:(float)displayPercent\n{\n    [super setDisplayPercent:displayPercent];\n    \n    displayPercent += 0.2;\n\n    displayPercent = MIN(MAX(0.0f, displayPercent), 1.0f);\n    displayPercent = 1.0 - displayPercent;\n\n    displayPercent *= displayPercent;\n    \n    self.haveFunCaption.transform = CGAffineTransformMakeTranslation(0.0f, 150.0f * (displayPercent));\n    self.button.transform = CGAffineTransformMakeTranslation(0.0f, -400.0f * (displayPercent));\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVFinishTutorialPage.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVFinishTutorialPage\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"576\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"4he-9P-osa\">\n                    <rect key=\"frame\" x=\"275\" y=\"213\" width=\"150\" height=\"150\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <state key=\"normal\" image=\"TutorialFinishButton\"/>\n                </button>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialHaveFun\" id=\"igc-up-W4w\">\n                    <rect key=\"frame\" x=\"277\" y=\"446\" width=\"146\" height=\"28\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <outlet property=\"button\" destination=\"4he-9P-osa\" id=\"K5g-za-hbb\"/>\n                <outlet property=\"haveFunCaption\" destination=\"igc-up-W4w\" id=\"qEm-mi-gBh\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TutorialFinishButton\" width=\"150\" height=\"150\"/>\n        <image name=\"TutorialHaveFun\" width=\"146\" height=\"28\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVFloatAnimation.h",
    "content": "//\n//  RVFloatAnimation.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAnimation.h\"\n\n@interface RVFloatAnimation : RVAnimation\n\n@property (nonatomic) float from;\n@property (nonatomic) float to;\n\n- (float)valueForProgress:(float)progress;\n+ (RVFloatAnimation *)floatAnimationFromValue:(float)fromValue toValue:(float)toValue withDuration:(NSTimeInterval)duration;\n\n@end\n"
  },
  {
    "path": "Revolved/RVFloatAnimation.m",
    "content": "//\n//  RVFloatAnimation.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVFloatAnimation.h\"\n\n@implementation RVFloatAnimation\n\n- (float)valueForProgress:(float)progress\n{\n    return _from + (_to - _from) * progress;\n}\n\n+ (RVFloatAnimation *)floatAnimationFromValue:(float)fromValue toValue:(float)toValue withDuration:(NSTimeInterval)duration\n{\n    RVFloatAnimation *floatAnimation = [RVFloatAnimation new];\n    floatAnimation.from = fromValue;\n    floatAnimation.to = toValue;\n    floatAnimation.duration = duration;\n    \n    return floatAnimation;\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVGuideline.h",
    "content": "//\n//  RVGuideline.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 11.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface RVGuideline : NSObject\n\n@property (nonatomic) BOOL enabled;\n\n@property (nonatomic) GLKVector2 start;\n@property (nonatomic) GLKVector2 end;\n\n@property (nonatomic) GLKVector2 direction;\n@property (nonatomic) float length;\n\n@end\n"
  },
  {
    "path": "Revolved/RVGuideline.m",
    "content": "//\n//  RVGuideline.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 11.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVGuideline.h\"\n\n@implementation RVGuideline\n\n@end\n"
  },
  {
    "path": "Revolved/RVGuidelineDotSprite.h",
    "content": "//\n//  RVGuidelineDotSprite.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 04.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSprite.h\"\n\n@interface RVGuidelineDotSprite : RVSprite\n\n@property (nonatomic) GLKVector2 position;\n\n@property (nonatomic) float alpha;\n@property (nonatomic) float scale;\n\n@end\n"
  },
  {
    "path": "Revolved/RVGuidelineDotSprite.m",
    "content": "//\n//  RVGuidelineDotSprite.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 04.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVGuidelineDotSprite.h\"\n\n@implementation RVGuidelineDotSprite\n\n@end\n"
  },
  {
    "path": "Revolved/RVGuidlineDotMeshController.h",
    "content": "//\n//  RVGuidlineDotMeshController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 04.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVMeshController.h\"\n\n@interface RVGuidlineDotMeshController : RVMeshController\n\n@property (nonatomic) float dotSize;\n\n- (void)updateBuffersWithGuidelineDotSprites:(NSArray *)dotSprites;\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVGuidlineDotMeshController.m",
    "content": "//\n//  RVGuidlineDotMeshController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 04.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVGuidlineDotMeshController.h\"\n#import \"RVMeshController_Private.h\"\n#import \"BCShader.h\"\n\n#import \"RVGuidelineDotSprite.h\"\n#import \"PointVertex.h\"\n\n\nstatic const float UVSize = 0.0625f;\nstatic const GLKVector2 UVs[4] = {\n    {0.0f + UVSize, 0.5f + UVSize},\n    {0.0f         , 0.5f + UVSize},\n    {0.0f + UVSize, 0.5f},\n    {0.0f         , 0.5f},\n};\n\n\nstatic const NSUInteger VertexLimit = 1024;\nstatic const NSUInteger IndexLimit = VertexLimit * 2;\n\n@implementation RVGuidlineDotMeshController\n\n- (void)setupVAO\n{\n    glGenVertexArraysOES(1, &_VAO);\n    glBindVertexArrayOES(_VAO);\n    \n    \n    glGenBuffers(1, &_vertexBuffer);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    glBufferData(GL_ARRAY_BUFFER, VertexLimit * sizeof(PointVertex), NULL, GL_DYNAMIC_DRAW);\n    \n    glGenBuffers(1, &_indexBuffer);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, IndexLimit * sizeof(GLushort), NULL, GL_DYNAMIC_DRAW);\n    \n    glEnableVertexAttribArray(VertexAttribPosition);\n    glVertexAttribPointer(VertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(PointVertex), (void *)offsetof(PointVertex, p));\n    \n    glEnableVertexAttribArray(VertexAttribTexCoord);\n    glVertexAttribPointer(VertexAttribTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(PointVertex), (void *)offsetof(PointVertex, uv));\n    \n    glEnableVertexAttribArray(VertexAttribAlpha);\n    glVertexAttribPointer(VertexAttribAlpha,    1, GL_FLOAT, GL_FALSE, sizeof(PointVertex), (void *)offsetof(PointVertex, alpha));\n    \n    glBindVertexArrayOES(0);\n}\n\n- (void)updateBuffersWithGuidelineDotSprites:(NSArray *)dotSprites;\n{\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    PointVertex *vertexData = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    GLushort *indexData = glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    PointVertex v[4];\n    v[0].uv = UVs[0];\n    v[1].uv = UVs[1];\n    v[2].uv = UVs[2];\n    v[3].uv = UVs[3];\n    \n    GLushort i[6];\n    \n    GLuint totalIndicies = 0;\n    GLuint totalVertices = 0;\n    \n    for (RVGuidelineDotSprite *dotSprite in dotSprites) {\n        \n        if (totalVertices + 4 > VertexLimit) {\n            break;\n        }\n        \n        float alpha = dotSprite.alpha;\n        float size = dotSprite.scale * _dotSize/2.0;\n        \n        GLKVector2 center = dotSprite.position;\n        v[0].p = GLKVector2Make(center.x + size, center.y + size);\n        v[1].p = GLKVector2Make(center.x - size, center.y + size);\n        v[2].p = GLKVector2Make(center.x + size, center.y - size);\n        v[3].p = GLKVector2Make(center.x - size, center.y - size);\n        \n        v[0].alpha = alpha;\n        v[1].alpha = alpha;\n        v[2].alpha = alpha;\n        v[3].alpha = alpha;\n        \n        memcpy(vertexData, v, sizeof(v));\n        vertexData += sizeof(v)/sizeof(v[0]);\n        \n        i[0] = totalVertices + 0;\n        i[1] = totalVertices + 2;\n        i[2] = totalVertices + 1;\n        \n        i[3] = totalVertices + 1;\n        i[4] = totalVertices + 2;\n        i[5] = totalVertices + 3;\n        \n        memcpy(indexData, i, sizeof(i));\n        indexData += sizeof(i)/sizeof(i[0]);\n        \n        totalIndicies += 6;\n        totalVertices += 4;\n    }\n    \n    _indiciesCount = totalIndicies;\n\n    glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);\n    glUnmapBufferOES(GL_ARRAY_BUFFER);\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVLineMeshController.h",
    "content": "//\n//  LineController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVMeshController.h\"\n\n@interface RVLineMeshController : RVMeshController\n\n@property (nonatomic) float lineSize;\n\n- (void)updateBuffersWithLineSprites:(NSArray *)lineSprites;\n\n@end\n"
  },
  {
    "path": "Revolved/RVLineMeshController.m",
    "content": "//\n//  LineController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVLineMeshController.h\"\n#import \"RVMeshController_Private.h\"\n#import \"RVColorProvider.h\"\n#import \"BCShader.h\"\n#import \"RVSegment.h\"\n\n#import \"LineVertex.h\"\n#import \"RVLineSprite.h\"\n\nstatic const NSUInteger VertexLimit = USHRT_MAX;\nstatic const NSUInteger IndexLimit = VertexLimit * 4;\n\n\nstatic const NSUInteger VerticesInSegment = 2;\nstatic const NSUInteger IndiciesInSegment = 6;\n\n@interface RVLineMeshController()\n@end\n\n@implementation RVLineMeshController\n\n\n\n- (void)setupVAO\n{\n    glGenVertexArraysOES(1, &_VAO);\n    glBindVertexArrayOES(_VAO);\n    \n    \n    glGenBuffers(1, &_vertexBuffer);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    glBufferData(GL_ARRAY_BUFFER, VertexLimit * sizeof(LineVertex), NULL, GL_DYNAMIC_DRAW);\n    \n    glGenBuffers(1, &_indexBuffer);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, IndexLimit * sizeof(GLushort), NULL, GL_DYNAMIC_DRAW);\n    \n    glEnableVertexAttribArray(VertexAttribPosition);\n    glVertexAttribPointer(VertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(LineVertex), (void *)offsetof(LineVertex, p));\n    \n    glEnableVertexAttribArray(VertexAttribColor);\n    glVertexAttribPointer(VertexAttribColor,    3, GL_FLOAT, GL_FALSE, sizeof(LineVertex), (void *)offsetof(LineVertex, color));\n    \n    glBindVertexArrayOES(0);\n}\n\n- (void)updateBuffersWithLineSprites:(NSArray *)lineSprites\n{\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    LineVertex *vertexData = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    GLushort *indexData = glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    \n    GLuint totalIndicies = 0;\n    GLuint totalVertices = 0;\n    \n    for (RVLineSprite *sprite in lineSprites) {\n        NSUInteger verticesCount;\n        NSUInteger indiciesCount;\n        \n        BOOL hasFilledAll = [self tessellateSprite:sprite vertexData:vertexData indexData:indexData startVertexIndex:totalVertices verticesCount:&verticesCount indiciesCount:&indiciesCount];\n        \n        if (!hasFilledAll) {\n            break;\n        }\n        \n        sprite.indiciesCount = (GLuint)indiciesCount;\n        sprite.indiciesOffset = totalIndicies;\n        \n        totalIndicies += indiciesCount;\n        totalVertices += verticesCount;\n        \n        vertexData += verticesCount;\n        indexData += indiciesCount;\n    }\n    \n    \n    _indiciesCount = totalIndicies;\n    \n    glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);\n    glUnmapBufferOES(GL_ARRAY_BUFFER);\n}\n\n- (BOOL)tessellateSprite:(RVLineSprite *)sprite\n              vertexData:(LineVertex *)vertexData\n               indexData:(GLushort *)indexData\n        startVertexIndex:(NSUInteger)startVertex\n           verticesCount:(out NSUInteger *)verticesCount\n           indiciesCount:(out NSUInteger *)indiciesCount\n{\n    LineVertex v[VerticesInSegment];\n    GLushort i[IndiciesInSegment];\n    \n    NSUInteger totalIndicies = 0;\n    NSUInteger totalVertices = 0;\n    \n    GLKVector3 color = sprite.color;\n    v[0].color = v[1].color = color;\n    \n    NSUInteger tesselationSegments = sprite.tesselationSegments;\n    SegmentTesselator tessalator = sprite.tesselator;\n    \n    float burnout = sprite.burnout;\n    float widthMultiplier = sprite.widthMultiplier;\n    \n    if (startVertex + (tesselationSegments + 1) * VerticesInSegment > VertexLimit) {\n        return NO;\n    }\n    \n    for (int seg = 0; seg < tesselationSegments + 1; seg++) {\n        \n        SegmentTesselation tess = tessalator(burnout/2.0 + ((double)seg/(double)tesselationSegments) * (1.0 - burnout));\n        v[0].p = GLKVector2Add(tess.p, GLKVector2MultiplyScalar(tess.n, +_lineSize * widthMultiplier /2.0f));\n        v[1].p = GLKVector2Add(tess.p, GLKVector2MultiplyScalar(tess.n, -_lineSize * widthMultiplier/2.0f));\n        \n        memcpy(vertexData, v, sizeof(v));\n        vertexData += VerticesInSegment;\n        totalVertices += VerticesInSegment;\n    }\n    \n    for (int seg = 0; seg < tesselationSegments; seg++) {\n        \n        i[0] = startVertex + 0;\n        i[1] = startVertex + 2;\n        i[2] = startVertex + 1;\n        \n        i[3] = startVertex + 1;\n        i[4] = startVertex + 2;\n        i[5] = startVertex + 3;\n        \n        memcpy(indexData, i, sizeof(i));\n        indexData += IndiciesInSegment;\n        totalIndicies += IndiciesInSegment;\n        \n        startVertex += VerticesInSegment;\n    }\n    \n    *verticesCount = totalVertices;\n    *indiciesCount = totalIndicies;\n    \n    return YES;\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVLineShader.fsh",
    "content": "\nvarying lowp vec4 colorVarying;\n\nvoid main()\n{\n    gl_FragColor = colorVarying;\n}\n\n"
  },
  {
    "path": "Revolved/RVLineShader.h",
    "content": "//\n//  LineShader.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"BCShader.h\"\n\n@interface RVLineShader : BCShader\n\n@property (nonatomic) GLint viewProjectionMatrixUniform;\n\n@end\n"
  },
  {
    "path": "Revolved/RVLineShader.m",
    "content": "//\n//  LineShader.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVLineShader.h\"\n\n@implementation RVLineShader\n\n- (void)bindAttributeLocations\n{\n    glBindAttribLocation(self.program, VertexAttribPosition, \"position\");\n    glBindAttribLocation(self.program, VertexAttribColor, \"color\");\n}\n\n- (void)getUniformLocations\n{\n    self.viewProjectionMatrixUniform = glGetUniformLocation(self.program, \"viewProjectionMatrix\");\n}\n\n- (NSString *)shaderName\n{\n    return @\"RVLineShader\";\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVLineShader.vsh",
    "content": "\nattribute vec4 position;\nattribute vec4 color;\n\nvarying vec4 colorVarying;\n\nuniform mat4 viewProjectionMatrix;\n\nvoid main()\n{\n    colorVarying = color;\n    \n    gl_Position = viewProjectionMatrix * position;\n}\n\n"
  },
  {
    "path": "Revolved/RVLineSprite.h",
    "content": "//\n//  RVLineSprite.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 19.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSprite.h\"\n#import \"RVSegment.h\"\n\n@interface RVLineSprite : RVSprite\n\n@property (nonatomic) GLKVector3 color;\n@property (nonatomic) float burnout;\n@property (nonatomic) float widthMultiplier;\n\n@property (nonatomic, strong) SegmentTesselator tesselator;\n@property (nonatomic) NSUInteger tesselationSegments;\n\n@end\n"
  },
  {
    "path": "Revolved/RVLineSprite.m",
    "content": "//\n//  RVLineSprite.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 19.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVLineSprite.h\"\n\n@implementation RVLineSprite\n\n@end\n"
  },
  {
    "path": "Revolved/RVMeshController.h",
    "content": "//\n//  RVMeshController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface RVMeshController : NSObject\n\n@property (nonatomic, readonly) GLuint VAO;\n@property (nonatomic, readonly) GLuint indiciesCount;\n\n- (void)setupOpenGL;\n\n@end\n"
  },
  {
    "path": "Revolved/RVMeshController.m",
    "content": "//\n//  RVMeshController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVMeshController.h\"\n#import \"RVMeshController_Private.h\"\n\n@implementation RVMeshController\n\n- (void)setupOpenGL\n{\n    [self setupVAO];\n}\n\n- (void)setupVAO\n{\n    NSAssert(0, @\"Don't call me\");\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVMeshController_Private.h",
    "content": "//\n//  RVMeshController_Private.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVMeshController.h\"\n\n@interface RVMeshController ()\n{\n    @protected\n    GLuint _VAO;\n    GLuint _indiciesCount;\n    \n    GLuint _indexBuffer;\n    GLuint _vertexBuffer;\n\n}\n\n- (void)setupVAO;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModel.h",
    "content": "//\n//  RVModel.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface RVModel : NSObject\n\n@property (nonatomic, strong) NSMutableOrderedSet *segments;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModel.m",
    "content": "//\n//  RVModel.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModel.h\"\n\n@implementation RVModel\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        self.segments = [NSMutableOrderedSet new];\n    }\n    return self;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelButtonsView.h",
    "content": "//\n//  RVModelButtonsView.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 17.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVModelButtonsView : UIView\n\n@property (weak, nonatomic) IBOutlet UIButton *cloneButton;\n@property (weak, nonatomic) IBOutlet UIButton *shareButton;\n@property (weak, nonatomic) IBOutlet UIButton *confirmTrashButton;\n\n- (void)setTrashCanMode:(BOOL)trashCanMode animated:(BOOL)animated;\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelButtonsView.m",
    "content": "//\n//  RVModelButtonsView.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 17.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelButtonsView.h\"\n\n@interface RVModelButtonsView()\n\n@property (weak, nonatomic) IBOutlet UIView *trashContainer;\n@property (weak, nonatomic) IBOutlet UIImageView *lidImageView;\n@property (weak, nonatomic) IBOutlet UIImageView *canImageView;\n\n@property (weak, nonatomic) IBOutlet UIButton *trashButton;\n@property (weak, nonatomic) IBOutlet UIButton *declineTrashButton;\n@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *allButtons;\n\n@end\n\n@implementation RVModelButtonsView\n\n- (void)awakeFromNib\n{\n    [super awakeFromNib];\n    self.lidImageView.image = [self.lidImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];\n    self.canImageView.image = [self.canImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];\n    self.backgroundColor = nil;\n    \n    for (UIButton *button in self.allButtons) {\n        button.exclusiveTouch = YES;\n    }\n    \n    [self setTrashCanMode:NO animated:NO];\n}\n\n- (IBAction)trashButtonTapped:(UIButton *)sender\n{\n    [self setTrashCanMode:YES animated:YES];\n}\n\n- (IBAction)declineTrashButtonTapped:(UIButton *)sender\n{\n    [self setTrashCanMode:NO animated:YES];\n}\n\n- (IBAction)confirmTrashButtonTapped:(id)sender\n{\n    self.userInteractionEnabled = NO;\n}\n\n- (void)setTrashCanMode:(BOOL)trashCanMode animated:(BOOL)animated\n{\n    NSTimeInterval Duration = animated ? 0.25 : 0.0;\n    CGFloat Scale = 0.05;\n    CGFloat TrashQuestionAlpha = 0.75f;\n    CGFloat TrashQuestionScale = 0.75f;\n    \n    if (trashCanMode) {\n        self.trashButton.hidden = YES;\n        self.trashContainer.hidden = NO;\n        \n\n        [UIView animateWithDuration:Duration/2.0f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{\n            self.shareButton.transform = CGAffineTransformMakeScale(Scale, Scale);\n            self.cloneButton.transform = CGAffineTransformMakeScale(Scale, Scale);\n        } completion:^(BOOL finished) {\n\n            self.declineTrashButton.alpha = 1.0f;\n            self.confirmTrashButton.alpha = 1.0f;\n            self.shareButton.alpha = 0.0f;\n            self.cloneButton.alpha = 0.0f;\n            [UIView animateWithDuration:Duration/2.0f delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{\n                self.confirmTrashButton.transform = CGAffineTransformIdentity;\n                self.declineTrashButton.transform = CGAffineTransformIdentity;\n            } completion:NULL];\n        }];\n        \n        [UIView animateWithDuration:Duration animations:^{\n            self.lidImageView.transform = CGAffineTransformMakeRotation(1.2*M_PI);\n            self.trashContainer.alpha = TrashQuestionAlpha;\n            self.trashContainer.transform = CGAffineTransformMakeScale(TrashQuestionScale, TrashQuestionScale);\n        }];\n    } else {\n        [UIView animateWithDuration:Duration/2.0f delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{\n            self.confirmTrashButton.transform = CGAffineTransformMakeScale(Scale, Scale);\n            self.declineTrashButton.transform = CGAffineTransformMakeScale(Scale, Scale);\n        } completion:^(BOOL finished) {\n\n            self.declineTrashButton.alpha = 0.0f;\n            self.confirmTrashButton.alpha = 0.0f;\n            self.shareButton.alpha = 1.0f;\n            self.cloneButton.alpha = 1.0f;\n\n            [UIView animateWithDuration:Duration/2.0f delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{\n                self.shareButton.transform = CGAffineTransformIdentity;\n                self.cloneButton.transform = CGAffineTransformIdentity;\n            } completion:NULL];\n        }];\n        \n        \n        [UIView animateWithDuration:Duration animations:^{\n            self.lidImageView.transform = CGAffineTransformIdentity;\n            self.trashContainer.alpha = 1.0f;\n            self.trashContainer.transform = CGAffineTransformIdentity;\n            \n        } completion:^(BOOL finished) {\n            self.trashButton.hidden = NO;\n            self.trashContainer.hidden = YES;\n        }];\n    }\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelButtonsView.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVModelButtonsView\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"204\" height=\"54\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n            <subviews>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"mfO-kE-65V\" userLabel=\"Clone Button\">\n                    <rect key=\"frame\" x=\"142\" y=\"0.0\" width=\"62\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <state key=\"normal\" image=\"CloneButton\"/>\n                    <state key=\"selected\" image=\"DotsSelected\"/>\n                </button>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"mff-b3-bmL\" userLabel=\"Share Button\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"62\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <state key=\"normal\" image=\"ShareButton\"/>\n                    <state key=\"selected\" image=\"DotsSelected\"/>\n                </button>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"HVF-FD-mPo\" userLabel=\"Decline Button\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"62\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <state key=\"normal\" image=\"DeclineButton\"/>\n                    <state key=\"selected\" image=\"DotsSelected\"/>\n                    <connections>\n                        <action selector=\"declineTrashButtonTapped:\" destination=\"1\" eventType=\"touchUpInside\" id=\"yWq-8E-iXa\"/>\n                    </connections>\n                </button>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"QKC-b7-sXu\" userLabel=\"Confirm Button\">\n                    <rect key=\"frame\" x=\"142\" y=\"0.0\" width=\"62\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <state key=\"normal\" image=\"ConfirmButton\"/>\n                    <state key=\"selected\" image=\"DotsSelected\"/>\n                    <connections>\n                        <action selector=\"confirmTrashButtonTapped:\" destination=\"1\" eventType=\"touchUpInside\" id=\"r2b-eF-PGs\"/>\n                    </connections>\n                </button>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"hGN-yx-4Ke\" userLabel=\"Trash Button\">\n                    <rect key=\"frame\" x=\"71\" y=\"0.0\" width=\"62\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                    <state key=\"normal\" image=\"TrashButton\"/>\n                    <state key=\"selected\" image=\"TrashButton\"/>\n                    <connections>\n                        <action selector=\"trashButtonTapped:\" destination=\"1\" eventType=\"touchUpInside\" id=\"EAg-ha-vRN\"/>\n                    </connections>\n                </button>\n                <view contentMode=\"scaleToFill\" id=\"pzj-9B-LKP\">\n                    <rect key=\"frame\" x=\"70\" y=\"-9\" width=\"64\" height=\"73\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <subviews>\n                        <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TrashLid\" id=\"bUO-yC-SWg\">\n                            <rect key=\"frame\" x=\"-2\" y=\"20\" width=\"46\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                        </imageView>\n                        <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TrashCan\" id=\"wBE-rA-J4R\">\n                            <rect key=\"frame\" x=\"22\" y=\"27\" width=\"20\" height=\"26\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                        </imageView>\n                    </subviews>\n                </view>\n            </subviews>\n            <connections>\n                <outlet property=\"canImageView\" destination=\"wBE-rA-J4R\" id=\"duX-ol-dRi\"/>\n                <outlet property=\"cloneButton\" destination=\"mfO-kE-65V\" id=\"psE-WU-SuD\"/>\n                <outlet property=\"confirmTrashButton\" destination=\"QKC-b7-sXu\" id=\"Rjo-df-G4h\"/>\n                <outlet property=\"declineTrashButton\" destination=\"HVF-FD-mPo\" id=\"lkI-Ce-Cjb\"/>\n                <outlet property=\"lidImageView\" destination=\"bUO-yC-SWg\" id=\"V1X-A9-aY6\"/>\n                <outlet property=\"shareButton\" destination=\"mff-b3-bmL\" id=\"cCv-kZ-yrM\"/>\n                <outlet property=\"trashButton\" destination=\"hGN-yx-4Ke\" id=\"T3Z-fj-idI\"/>\n                <outlet property=\"trashContainer\" destination=\"pzj-9B-LKP\" id=\"Dao-IW-3rO\"/>\n                <outletCollection property=\"allButtons\" destination=\"mfO-kE-65V\" id=\"Rit-k5-QNa\"/>\n                <outletCollection property=\"allButtons\" destination=\"mff-b3-bmL\" id=\"l2U-yb-fzM\"/>\n                <outletCollection property=\"allButtons\" destination=\"HVF-FD-mPo\" id=\"iYX-J2-kNd\"/>\n                <outletCollection property=\"allButtons\" destination=\"QKC-b7-sXu\" id=\"EyL-2R-a19\"/>\n                <outletCollection property=\"allButtons\" destination=\"hGN-yx-4Ke\" id=\"Qw1-T4-UpA\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"CloneButton\" width=\"24\" height=\"28\"/>\n        <image name=\"ConfirmButton\" width=\"26\" height=\"20\"/>\n        <image name=\"DeclineButton\" width=\"20\" height=\"20\"/>\n        <image name=\"DotsSelected\" width=\"44\" height=\"26\"/>\n        <image name=\"ShareButton\" width=\"24\" height=\"34\"/>\n        <image name=\"TrashButton\" width=\"24\" height=\"32\"/>\n        <image name=\"TrashCan\" width=\"20\" height=\"26\"/>\n        <image name=\"TrashLid\" width=\"46\" height=\"16\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVModelCell.h",
    "content": "//\n//  RVModelCell.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@class RVModelButtonsView;\n\n@interface RVModelCell : UITableViewCell\n\n@property (nonatomic, strong, readonly) UIView *buttonsContainerView;\n@property (nonatomic, strong, readonly) RVModelButtonsView *buttonsView;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelCell.m",
    "content": "//\n//  RVModelCell.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelCell.h\"\n#import \"RVModelButtonsView.h\"\n\n@implementation RVModelCell\n\n- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier\n{\n    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];\n    if (self) {\n        self.backgroundColor = nil;\n        self.selectionStyle = UITableViewCellSelectionStyleNone;\n        \n        self.contentView.superview.clipsToBounds = NO;\n        _buttonsView = [[NSBundle mainBundle] loadNibNamed:@\"RVModelButtonsView\" owner:self options:nil][0];\n        _buttonsView.alpha = 0.0f;\n        \n\n        _buttonsContainerView = [[UIView alloc] initWithFrame:_buttonsView.bounds];\n        _buttonsContainerView.backgroundColor = nil;\n        \n        [_buttonsContainerView addSubview:_buttonsView];\n        [self.contentView addSubview:_buttonsContainerView];\n    }\n    return self;\n}\n\n- (void)prepareForReuse\n{\n    [super prepareForReuse];\n    self.buttonsView.userInteractionEnabled = YES;\n}\n\n- (void)layoutSubviews\n{\n    [super layoutSubviews];\n    \n    _buttonsContainerView.center = CGPointMake(_buttonsView.bounds.size.height/2.0f + 3.0f, self.contentView.frame.size.height/2.0);\n    _buttonsContainerView.transform = CGAffineTransformMakeRotation(M_PI_2);\n}\n\n- (void)setEditing:(BOOL)editing animated:(BOOL)animated\n{\n    [super setEditing:editing animated:animated];\n    \n    [UIView animateWithDuration:0.2 animations:^{\n        self.buttonsView.alpha = editing ? 1.0f : 0.0f;\n    } completion:^(BOOL finished) {\n        if (finished && !editing) {\n            [self.buttonsView setTrashCanMode:NO animated:NO];\n        }\n    }];\n}\n@end\n"
  },
  {
    "path": "Revolved/RVModelManager.h",
    "content": "//\n//  RVModelManager.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@class RVModel;\n@interface RVModelManager : NSObject\n\n- (void)loadModels;\n- (NSUInteger)numberOfModels;\n\n- (RVModel *)createNewModel;\n- (void)saveModel:(RVModel *)model;\n\n- (RVModel *)modelAtIndex:(NSUInteger)modelIndex;\n- (void)moveModelAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)targetIndex;\n- (void)cloneModelAtIndex:(NSUInteger)modelIndex;\n- (void)deleteModelAtIndex:(NSUInteger)modelIndex;\n\n- (BOOL)importModelData:(NSData *)data error:(NSError **)error;\n\n+ (NSData *)exportDataForModel:(RVModel *)model;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelManager.m",
    "content": "//\n//  RVFileManager.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelManager.h\"\n#import \"RVModel.h\"\n#import \"RVModelMetadata.h\"\n#import \"RVModelSerializer.h\"\n\n#import \"NSError+RevolvedErrors.h\"\n#import \"NSArray+Functional.h\"\n\n#import \"NSMutableArray+MoveObject.h\"\n#import \"NSMutableOrderedSet+MoveObject.h\"\n\n\nstatic const NSInteger FileMajorVersion = 1;\nstatic const NSInteger FileMinorVersion = 0;\n\nstatic NSString * const MetadataModelsKey = @\"models\";\n\nstatic NSString * const FileMajorVersionKey = @\"major\";\nstatic NSString * const FileMinorVersionKey = @\"minor\";\nstatic NSString * const FileModelKey = @\"model\";\n\n@interface RVModelManager()\n\n@property (nonatomic, strong) NSMutableOrderedSet *models;\n@property (nonatomic, strong) NSMutableArray *modelMetadatas;\n\n@end\n\n\n@implementation RVModelManager\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _models = [NSMutableOrderedSet orderedSet];\n        [self loadMetadata];\n        [self loadModels];\n    }\n    return self;\n}\n\n#pragma mark - Path Operations\n\n- (NSString *)modelsPath\n{\n    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);\n    NSString *documentsDirectory = [paths objectAtIndex:0];\n    NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@\"Models\"];\n    \n    NSError *error;\n    \n    if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {\n        [[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error];\n    }\n    \n    return dataPath;\n}\n\n- (NSString *)metadataPath\n{\n    return [[self modelsPath] stringByAppendingPathComponent:@\"meta.data\"];\n}\n\n\n- (NSString *)pathForModelAtIndex:(NSUInteger)modelIndex\n{\n    NSString *fileName = [self.modelMetadatas[modelIndex] fileName];\n    return [[self modelsPath] stringByAppendingPathComponent:fileName];\n}\n\n#pragma mark - Save/Load\n\n- (void)loadMetadata\n{\n    NSData *data = [NSData dataWithContentsOfFile:[self metadataPath]];\n    NSArray *metadatas;\n    NSError *error;\n    \n    if (data) {\n        NSDictionary *parsedJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];\n        if (parsedJSON) {\n            metadatas =[parsedJSON[MetadataModelsKey] mapObjectsUsingBlock:^id(NSDictionary *json, NSUInteger idx) {\n                return [RVModelMetadata modelMetadataFromJSON:json];\n            }];\n        }\n    }\n    \n    self.modelMetadatas = [NSMutableArray arrayWithArray:metadatas];\n}\n\n- (void)saveMetadata\n{\n    NSError *error;\n    \n    NSArray *jsonedMetadatas = [self.modelMetadatas mapObjectsUsingBlock:^id(RVModelMetadata *metadata, NSUInteger idx) {\n        return [metadata toJSON];\n    }];\n    \n    NSDictionary *metadata = @{MetadataModelsKey : jsonedMetadatas ?: @[]};\n    \n    NSData *data = [NSJSONSerialization dataWithJSONObject:metadata options:0 error:&error];\n    [data writeToFile:[self metadataPath] atomically:YES];\n}\n\n\n\n- (void)loadModels\n{\n    NSError *error;\n    NSUInteger count = [self.modelMetadatas count];\n    \n    NSMutableIndexSet *invalidIndexes = [NSMutableIndexSet indexSet];\n    \n    for (NSUInteger i = 0; i < count; i++) {\n        NSData *jsonData = [NSData dataWithContentsOfFile:[self pathForModelAtIndex:i]];\n        if (!jsonData) {\n            [invalidIndexes addIndex:i];\n            continue;\n        }\n        NSDictionary *modelDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];\n        if (modelDictionary == nil) {\n            [invalidIndexes addIndex:i];\n            continue;\n        }\n        \n        RVModel *model = [self modelWithDictionary:modelDictionary error:&error];\n        if (! model) {\n            [invalidIndexes addIndex:i];\n            continue;\n        }\n        \n        [self.models addObject:model];\n    }\n    \n    if (invalidIndexes.count > 0) {\n        NSLog(@\"INVALID DATA!!!\");\n    }\n    \n    [self.modelMetadatas removeObjectsAtIndexes:invalidIndexes];\n    \n    NSAssert(self.models.count == [self.modelMetadatas count], @\"Models array does not match metadata\");\n}\n\n\n- (void)saveModel:(RVModel *)model\n{\n    NSError *error;\n    NSUInteger modelIndex = [self.models indexOfObject:model];\n    if (modelIndex == NSNotFound) {\n        return;\n    }\n    \n    NSDictionary *modelDictionary = [RVModelManager dictionaryForModel:model];\n    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:modelDictionary options:0 error:&error];\n    if (jsonData) {\n        [jsonData writeToFile:[self pathForModelAtIndex:modelIndex] atomically:YES];\n    } else {\n        NSLog(@\"Error serializing model - %@\", error.localizedDescription);\n    }\n}\n\n#pragma mark -\n\n- (NSString *)newFileName\n{\n    NSInteger max = 0;\n    \n    for (RVModelMetadata *metadata in self.modelMetadatas) {\n        max = MAX(max, [metadata.fileName integerValue]);\n    }\n    \n    return [@(max + 1) stringValue];\n}\n\n- (void)addModelToDatabase:(RVModel *)model imported:(BOOL)imported\n{\n    RVModelMetadata *metadata = [RVModelMetadata new];\n    metadata.fileName = [self newFileName];\n    metadata.imported = imported;\n    \n    [self.modelMetadatas insertObject:metadata atIndex:0];\n    [self saveMetadata];\n    \n    [self.models insertObject:model atIndex:0];\n    [self saveModel:model];\n}\n\n\n\n#pragma mark -\n\n- (NSUInteger)numberOfModels\n{\n    return self.models.count;\n}\n\n\n- (RVModel *)createNewModel\n{\n    RVModel *newModel = [[RVModel alloc] init];\n    [self addModelToDatabase:newModel imported:NO];\n    \n    return newModel;\n}\n\n- (RVModel *)modelAtIndex:(NSUInteger)modelIndex\n{\n    return self.models[modelIndex];\n}\n\n- (void)moveModelAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)targetIndex\n{\n    [self.modelMetadatas moveObjectAtIndex:sourceIndex toIndex:targetIndex];\n    [self.models moveObjectAtIndex:sourceIndex toIndex:targetIndex];\n    \n    [self saveMetadata];\n}\n\n- (void)deleteModelAtIndex:(NSUInteger)modelIndex\n{\n    NSAssert(modelIndex < self.models.count, @\"Model index of out range\");\n\n    NSString *path = [self pathForModelAtIndex:modelIndex];\n    \n    NSError *error;\n    [self.modelMetadatas removeObjectAtIndex:modelIndex];\n    [self.models removeObjectAtIndex:modelIndex];\n    \n    if (![[NSFileManager defaultManager] removeItemAtPath:path error:&error]) {\n        NSLog(@\"Error deleting model\");\n    }\n    \n    [self saveMetadata];\n}\n\n- (void)cloneModelAtIndex:(NSUInteger)modelIndex\n{\n    NSError *error;\n    RVModel *sourceModel = self.models[modelIndex];\n    NSDictionary *sourceDictionary = [RVModelManager  dictionaryForModel:sourceModel];\n    RVModel *copiedModel = [self modelWithDictionary:sourceDictionary error:&error];\n    \n    \n    RVModelMetadata *metadata = [RVModelMetadata new];\n    metadata.fileName = [self newFileName];\n    \n    [self.modelMetadatas insertObject:metadata atIndex:modelIndex + 1];\n    [self.models insertObject:copiedModel atIndex:modelIndex + 1];\n\n    [self saveModel:copiedModel];\n    [self saveMetadata];\n}\n\n#pragma mark - Import/Export\n\n- (BOOL)importModelData:(NSData *)data error:(NSError **)error\n{\n    NSError *parseError;\n    NSDictionary *documentDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];\n    \n    if (!documentDict) {\n        *error = [NSError malformedFileError];\n        return NO;\n    }\n    \n    \n    RVModel *model = [self modelWithDictionary:documentDict error:&parseError];\n    if (!model) {\n        *error = parseError;\n        return NO;\n    }\n    \n    [self addModelToDatabase:model imported:YES];\n    \n    return YES;\n}\n\n+ (NSData *)exportDataForModel:(RVModel *)model\n{\n    \n    NSError *error;\n    NSDictionary *modelDictionary = [RVModelManager dictionaryForModel:model];\n    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:modelDictionary options:0 error:&error];\n    \n    return jsonData;\n}\n\n#pragma mark - Model Serialization\n\n+ (NSDictionary *)dictionaryForModel:(RVModel *)model\n{\n    NSDictionary *jsonModel = [RVModelSerializer JSONModelDictionaryFromSegments:model.segments.set];\n    \n    return @{FileMajorVersionKey : @(FileMajorVersion),\n             FileMinorVersionKey : @(FileMinorVersion),\n             FileModelKey : jsonModel};\n\n}\n\n- (RVModel *)modelWithDictionary:(NSDictionary *)dictionary error:(NSError **)error\n{\n    if ([dictionary[FileMajorVersionKey] integerValue] > FileMajorVersion) {\n        if (error) {\n            *error = [NSError obsoleteAppVersionError];\n        }\n        \n        return nil;\n    }\n    \n    NSError *parseError = nil;\n    NSSet *segments = [RVModelSerializer segmentsFromJSONModelDictionary:dictionary[FileModelKey] error:&parseError];\n    \n    if (!segments) {\n        *error = parseError;\n        return nil;\n    }\n    \n    RVModel *model = [[RVModel alloc] init];\n    model.segments = [NSMutableOrderedSet orderedSetWithSet:segments];\n    \n    return model;\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelMeshController.h",
    "content": "//\n//  MeshController.h\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 24.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVMeshController.h\"\n\n@interface RVModelMeshController : RVMeshController\n\n- (void)updateBuffersWithModelSprites:(NSArray *)modelSprites;\n\n@property (nonatomic, strong, readonly) NSArray *sprites;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelMeshController.m",
    "content": "//\n//  MeshController.m\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 24.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelMeshController.h\"\n#import \"RVMeshController_Private.h\"\n#import \"RVColorProvider.h\"\n#import \"BCShader.h\"\n#import \"RVSegment.h\"\n#import \"RVModelSprite.h\"\n\n#import \"Vertex.h\"\n#import \"Constants.h\"\n\nstatic const NSUInteger VertexLimit = USHRT_MAX;\nstatic const NSUInteger IndexLimit = VertexLimit * 4;\n\nstatic const float LengthTexScale = 2.0f;\nstatic const float RotTexScale = 2.0f;\n\n@interface RVModelMeshController()\n{\n    GLKMatrix4 _rotationMatrix;\n}\n\n@end\n\n@implementation RVModelMeshController\n\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _rotationMatrix = GLKMatrix4MakeRotation(2.0 * M_PI / (Spans * StripesPerSpan), 0.0, 1.0, 0.0);\n    }\n    return self;\n}\n\n- (void)setupVAO\n{\n    glGenVertexArraysOES(1, &_VAO);\n    glBindVertexArrayOES(_VAO);\n    \n    \n    glGenBuffers(1, &_vertexBuffer);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    glBufferData(GL_ARRAY_BUFFER, VertexLimit * sizeof(Vertex), NULL, GL_DYNAMIC_DRAW);\n    \n    glGenBuffers(1, &_indexBuffer);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, IndexLimit * sizeof(GLushort), NULL, GL_DYNAMIC_DRAW);\n    \n    glEnableVertexAttribArray(VertexAttribPosition);\n    glVertexAttribPointer(VertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, p));\n    \n    glEnableVertexAttribArray(VertexAttribNormal);\n    glVertexAttribPointer(VertexAttribNormal,   3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, n));\n    \n    glEnableVertexAttribArray(VertexAttribColor);\n    glVertexAttribPointer(VertexAttribColor,    3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, color));\n\n    glEnableVertexAttribArray(VertexAttribTexCoord);\n    glVertexAttribPointer(VertexAttribTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, uv));\n    \n    glBindVertexArrayOES(0);\n}\n\n- (void)updateBuffersWithModelSprites:(NSArray *)modelSprites\n{\n    _sprites = modelSprites;\n    \n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    Vertex *vertexData = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    GLushort *indexData = glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    \n    GLuint totalIndicies = 0;\n    GLuint totalVertices = 0;\n    \n    BOOL hasOverflownBuffer = NO;\n    \n    for (RVModelSprite *sprite in modelSprites) {\n        NSUInteger verticesCount = 0;\n        NSUInteger indiciesCount = 0;\n        \n        if (!hasOverflownBuffer && ![self tessellateSegments:sprite.drawnSegments vertexData:vertexData indexData:indexData startVertex:totalVertices verticesCount:&verticesCount indiciesCount:&indiciesCount]) {\n            hasOverflownBuffer = YES;\n        }\n        \n        sprite.indiciesCount = (GLuint)indiciesCount;\n        sprite.indiciesOffset = totalIndicies * sizeof(GLushort);\n        \n        totalIndicies += indiciesCount;\n        totalVertices += verticesCount;\n        \n        vertexData += verticesCount;\n        indexData += indiciesCount;\n    }\n    \n    _indiciesCount = totalIndicies;\n    \n    \n    glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);\n    glUnmapBufferOES(GL_ARRAY_BUFFER);\n}\n\n\n- (BOOL)tessellateSegments:(NSArray *)segments\n                vertexData:(Vertex *)vertexData\n                 indexData:(GLushort *)indexData\n               startVertex:(NSUInteger)startVertex\n             verticesCount:(out NSUInteger *)verticesCount\n             indiciesCount:(out NSUInteger *)indiciesCount\n{\n    const NSUInteger VerticesInRow = StripesPerSpan + 1;\n    const NSUInteger IndiciesInRow = StripesPerSpan * 6; // one quad has 2 triangles, each has 3 vertices\n    \n    Vertex vertexRow[VerticesInRow];\n    GLushort indexSpan[IndiciesInRow];\n    \n    NSUInteger totalIndicies = 0;\n    NSUInteger totalVertices = 0;\n    \n    for (RVSegment *segment in segments) {\n        \n        GLKVector3 color = [RVColorProvider vectorForColorIndex:segment.colorIndex];\n        for (int col = 0; col < VerticesInRow; col++) {\n            vertexRow[col].color = color;\n        }\n        \n        NSUInteger tesselationSegments = [segment modelTesselationSegments];\n        SegmentTesselator tessalator = segment.tesselator;\n        \n        if (startVertex + (tesselationSegments + 1) * VerticesInRow > VertexLimit) {\n            return NO;\n        }\n        \n        GLKVector2 previousP = tessalator(0.0).p;\n        float v = 0.0f;\n        for (int seg = 0; seg < tesselationSegments + 1; seg++) {\n            \n            SegmentTesselation tess = tessalator((double)seg/(double)tesselationSegments);\n            vertexRow[0].p = GLKVector3Make(tess.p.x, tess.p.y, 0.0);\n            vertexRow[0].n = GLKVector3Make(tess.n.x, tess.n.y, 0.0);\n            \n            v += LengthTexScale * GLKVector2Distance(tess.p, previousP);\n            previousP = tess.p;\n            \n            vertexRow[0].uv = GLKVector2Make(0.0f, v);\n            for (int col = 0; col < StripesPerSpan; col++) {\n                vertexRow[col + 1].p = GLKMatrix4MultiplyVector3(_rotationMatrix, vertexRow[col].p);\n                vertexRow[col + 1].n = GLKMatrix4MultiplyVector3(_rotationMatrix, vertexRow[col].n);\n                vertexRow[col + 1].uv = GLKVector2Make(RotTexScale * (col + 1.0f)/StripesPerSpan, v);\n            }\n            \n            memcpy(vertexData, vertexRow, sizeof(vertexRow));\n            vertexData += VerticesInRow;\n            totalVertices += VerticesInRow;\n        }\n        \n        for (int seg = 0; seg < tesselationSegments; seg++) {\n            \n            \n            for (int col = 0; col < StripesPerSpan; col++) {\n                indexSpan[col * 6 + 0] = startVertex + col + 0;\n                indexSpan[col * 6 + 1] = startVertex + col + VerticesInRow;\n                indexSpan[col * 6 + 2] = startVertex + col + 1;\n                \n                indexSpan[col * 6 + 3] = startVertex + col + 1;\n                indexSpan[col * 6 + 4] = startVertex + col + VerticesInRow;\n                indexSpan[col * 6 + 5] = startVertex + col + VerticesInRow + 1;\n            }\n            \n            memcpy(indexData, indexSpan, sizeof(indexSpan));\n            indexData += IndiciesInRow;\n            totalIndicies += IndiciesInRow;\n            startVertex += VerticesInRow;\n        }\n        startVertex += VerticesInRow;\n    }\n    \n    *verticesCount = totalVertices;\n    *indiciesCount = totalIndicies;\n\n    return YES;\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelMetadata.h",
    "content": "//\n//  RVModelMetadata.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface RVModelMetadata : NSObject\n\n@property (nonatomic, strong) NSString *fileName;\n@property (nonatomic) BOOL imported;\n\n+ (RVModelMetadata *)modelMetadataFromJSON:(NSDictionary *)json;\n- (NSDictionary *)toJSON;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelMetadata.m",
    "content": "//\n//  RVModelMetadata.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelMetadata.h\"\n\nstatic NSString * const FileNameKey = @\"fileName\";\nstatic NSString * const ImportedKey = @\"imported\";\n\n@implementation RVModelMetadata\n\n+ (RVModelMetadata *)modelMetadataFromJSON:(NSDictionary *)json\n{\n    RVModelMetadata *metadata = [RVModelMetadata new];\n    metadata.fileName = json[FileNameKey];\n    metadata.imported = [json[ImportedKey] boolValue];\n    \n    return metadata;\n}\n\n- (NSDictionary *)toJSON\n{\n    return @{FileNameKey : self.fileName ?: @\"\",\n             ImportedKey : @(self.imported)};\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelSerializer.h",
    "content": "//\n//  RVModelSerializer.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface RVModelSerializer : NSObject\n\n+ (NSSet *)segmentsFromJSONModelDictionary:(NSDictionary *)dictionary error:(NSError **)error;\n+ (NSDictionary *)JSONModelDictionaryFromSegments:(NSSet *)segments;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelSerializer.m",
    "content": "//\n//  RVModelSerializer.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelSerializer.h\"\n#import \"RVSegment.h\"\n\n#import \"RVEndPoint.h\"\n#import \"RVAnchorPoint.h\"\n#import \"RVControlPoint.h\"\n\n#import \"NSError+RevolvedErrors.h\"\n\nNSString * const SegmentsKey = @\"segments\";\nNSString * const ConnectionsKey = @\"connections\";\n\nNSString * const ColorKey = @\"colorIndex\";\nNSString * const EndPointsKey = @\"endPoints\";\nNSString * const ControlPointsKey = @\"controlPoints\";\n\nNSString * const PointXCoordinateKey = @\"x\";\nNSString * const PointYCoordinateKey = @\"y\";\nNSString * const PointIsSnappedKey = @\"snapped\";\n\nNSString * const ConnectionFromKey = @\"from\";\nNSString * const ConnectionToKey = @\"to\";\n\nNSString * const ConnectionSegmentIndex = @\"index\";\nNSString * const ConnectionSegmentEnd = @\"end\";\n\n@implementation RVModelSerializer\n\n+ (NSSet *)segmentsFromJSONModelDictionary:(NSDictionary *)dictionary error:(NSError **)error\n{\n\n    NSMutableOrderedSet *segments = [NSMutableOrderedSet orderedSet];\n\n    \n    if (![dictionary isKindOfClass:[NSDictionary class]]) {\n        goto error;\n    }\n    \n    __unsafe_unretained NSArray *jsonSegments = dictionary[SegmentsKey];\n    if (![jsonSegments isKindOfClass:[NSArray class]]) {\n        goto error;\n    }\n\n    \n    for (NSDictionary *segmentDict in jsonSegments) {\n        if (![segmentDict isKindOfClass:[NSDictionary class]]) {\n            goto error;\n        }\n        \n        RVSegment *segment = [[RVSegment alloc] init];\n        segment.colorIndex = [segmentDict[ColorKey] unsignedIntegerValue];\n        \n        // end points\n        \n        NSArray *endPoints = segmentDict[EndPointsKey];\n        if (![endPoints isKindOfClass:[NSArray class]]) {\n            goto error;\n        }\n        if (endPoints.count < 2) {\n            goto error;\n        }\n        \n        if (![self deserializeEndPointDictionary:endPoints[0] toEndPoint:segment.endPoints[0]]) {\n            goto error;\n        }\n        if (![self deserializeEndPointDictionary:endPoints[1] toEndPoint:segment.endPoints[1]]) {\n            goto error;\n        }\n        \n        // control points\n\n        \n        NSArray *controlPoints = segmentDict[ControlPointsKey];\n        if (![controlPoints isKindOfClass:[NSArray class]]) {\n            goto error;\n        }\n        if (controlPoints.count < 2) {\n            goto error;\n        }\n        \n        if (![self deserializeControlPointDictionary:controlPoints[0] toControlPoint:segment.controlPoints[0] anchorPoint:segment.anchorPoints[0]]) {\n            goto error;\n        }\n        if (![self deserializeControlPointDictionary:controlPoints[1] toControlPoint:segment.controlPoints[1] anchorPoint:segment.anchorPoints[1]]) {\n            goto error;\n        }\n        \n        [segment adjustAnchorPoints];\n        [segments addObject:segment];\n    }\n    \n    __unsafe_unretained NSArray *jsonConnections = dictionary[ConnectionsKey];\n    if (![jsonConnections isKindOfClass:[NSArray class]]) {\n        goto error;\n    }\n    \n    for (NSDictionary *connectionDict in jsonConnections) {\n        if (![connectionDict isKindOfClass:[NSDictionary class]]) {\n            goto error;\n        }\n        \n        \n        NSDictionary *from = connectionDict[ConnectionFromKey];\n        if (![from isKindOfClass:[NSDictionary class]]) {\n            goto error;\n        }\n        \n        NSUInteger aIndex = [from[ConnectionSegmentIndex] unsignedIntegerValue];\n        SegmentEnd aEnd = [from[ConnectionSegmentEnd] integerValue];\n        \n        \n        NSDictionary *to = connectionDict[ConnectionToKey];\n        if (![to isKindOfClass:[NSDictionary class]]) {\n            goto error;\n        }\n        \n        NSUInteger bIndex = [to[ConnectionSegmentIndex] unsignedIntegerValue];\n        SegmentEnd bEnd = [to[ConnectionSegmentEnd] integerValue];\n        \n        if (aIndex >= segments.count || bIndex >= segments.count) {\n            goto error;\n        }\n        \n        RVSegment *aSegment = segments[aIndex];\n        RVSegment *bSegment = segments[bIndex];\n        \n        [RVSegmentConnection connectSegment:aSegment bySegmentEnd:aEnd toSegment:bSegment atSegmentEnd:bEnd];\n    }\n    \n    if (error) {\n        *error = nil;\n    }\n    return segments.set;\n    \nerror:\n    \n    if (error) {\n        *error = [NSError malformedFileError];\n    }\n    return nil;\n}\n\n\n\n+ (NSDictionary *)JSONModelDictionaryFromSegments:(NSSet *)segments\n{\n    NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithSet:segments];\n    NSMutableSet *connections = [NSMutableSet set];\n    \n    NSMutableArray *jsonSegments = [NSMutableArray array];\n    for (RVSegment *segment in orderedSet) {\n        NSMutableDictionary *segmentDict = [NSMutableDictionary dictionary];\n        segmentDict[ColorKey] = @(segment.colorIndex);\n        \n        segmentDict[EndPointsKey] = @[[self serializeEndPoint:segment.endPoints[0]],\n                                      [self serializeEndPoint:segment.endPoints[1]]];\n        \n        segmentDict[ControlPointsKey] = @[[self serializeControlPoint:segment.controlPoints[0] isSnapped:[segment.anchorPoints[0] hasControlPoint]],\n                                          [self serializeControlPoint:segment.controlPoints[1] isSnapped:[segment.anchorPoints[1] hasControlPoint]]];\n        \n        if ([segment connectionAtSegmentEnd:SegmentEndFirst]) {\n            [connections addObject:[segment connectionAtSegmentEnd:SegmentEndFirst]];\n        }\n        if ([segment connectionAtSegmentEnd:SegmentEndSecond]) {\n            [connections addObject:[segment connectionAtSegmentEnd:SegmentEndSecond]];\n        }\n        \n        [jsonSegments addObject:segmentDict];\n    }\n    \n    NSMutableArray *jsonConnections = [NSMutableArray array];\n    for (RVSegmentConnection *connection in connections) {\n        NSDictionary *connectionDict = [self serializeConnection:connection withOrderedSegments:orderedSet];\n        [jsonConnections addObject:connectionDict];\n    }\n    \n    return @{SegmentsKey   : jsonSegments,\n             ConnectionsKey : jsonConnections};\n}\n\n+ (NSDictionary *)serializeEndPoint:(RVEndPoint *)endPoint\n{\n    return @{PointXCoordinateKey : @(endPoint.position.x),\n             PointYCoordinateKey : @(endPoint.position.y)};\n}\n\n+ (BOOL)deserializeEndPointDictionary:(NSDictionary *)endPointDict toEndPoint:(RVEndPoint *)endPoint\n{\n    if (![endPointDict isKindOfClass:[NSDictionary class]]) {\n        return NO;\n    }\n    \n    endPoint.position = GLKVector2Make([endPointDict[PointXCoordinateKey] floatValue],\n                                       [endPointDict[PointYCoordinateKey] floatValue]);\n    return YES;\n}\n\n\n\n+ (NSDictionary *)serializeControlPoint:(RVControlPoint *)controlPoint isSnapped:(BOOL)snapped;\n{\n    return @{PointXCoordinateKey : @(controlPoint.position.x),\n             PointYCoordinateKey : @(controlPoint.position.y),\n             PointIsSnappedKey   : @(snapped)};\n}\n\n+ (BOOL)deserializeControlPointDictionary:(NSDictionary *)controlPointDict toControlPoint:(RVControlPoint *)controlPoint anchorPoint:(RVAnchorPoint *)anchorPoint\n{\n    if (![controlPointDict isKindOfClass:[NSDictionary class]]) {\n        return NO;\n    }\n    \n    controlPoint.position = GLKVector2Make([controlPointDict[PointXCoordinateKey] floatValue],\n                                           [controlPointDict[PointYCoordinateKey] floatValue]);\n    anchorPoint.hasControlPoint = [controlPointDict[PointIsSnappedKey] boolValue];\n    \n    return YES;\n}\n\n\n\n+ (NSDictionary *)serializeConnection:(RVSegmentConnection *)connection withOrderedSegments:(NSOrderedSet *)segments\n{\n    NSAssert(connection, nil);\n    NSAssert(connection.a, nil);\n    NSAssert(connection.b, nil);\n    \n    return @{ConnectionFromKey : @{ConnectionSegmentIndex : @([segments indexOfObject:connection.a]),\n                                   ConnectionSegmentEnd   : @(connection.aEnd)},\n             ConnectionToKey   : @{ConnectionSegmentIndex : @([segments indexOfObject:connection.b]),\n                                   ConnectionSegmentEnd   : @(connection.bEnd)},\n             };\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelShader.fsh",
    "content": "\nvarying lowp vec4 colorVarying;\nvarying lowp vec2 texCoordVarying;\n\nuniform lowp sampler2D texSampler;\n\nvoid main()\n{\n    lowp vec4 color = texture2D(texSampler, texCoordVarying);\n\n    gl_FragColor = colorVarying * color;\n}\n\n"
  },
  {
    "path": "Revolved/RVModelShader.h",
    "content": "//\n//  PatternShader.h\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 25.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"BCShader.h\"\n\n@interface RVModelShader : BCShader\n\n@property (nonatomic) GLint viewProjectionModelMatrixUniform;\n@property (nonatomic) GLint normalModelMatrixUniform;\n@property (nonatomic) GLint texSamplerUniform;\n@property (nonatomic) GLint trigonometryUniform;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelShader.m",
    "content": "//\n//  PatternShader.m\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 25.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelShader.h\"\n\n@implementation RVModelShader\n\n- (void)bindAttributeLocations\n{\n    glBindAttribLocation(self.program, VertexAttribPosition, \"position\");\n    glBindAttribLocation(self.program, VertexAttribNormal, \"normal\");\n    glBindAttribLocation(self.program, VertexAttribColor, \"color\");\n    glBindAttribLocation(self.program, VertexAttribTexCoord, \"texCoord\");\n\n}\n\n- (void)getUniformLocations\n{\n    self.viewProjectionModelMatrixUniform = glGetUniformLocation(self.program, \"viewProjectionModelMatrix\");\n    self.normalModelMatrixUniform = glGetUniformLocation(self.program, \"normalModelMatrix\");\n    self.texSamplerUniform = glGetUniformLocation(self.program, \"texSampler\");\n    self.trigonometryUniform = glGetUniformLocation(self.program, \"trig\");\n}\n\n- (NSString *)shaderName\n{\n    return @\"RVModelShader\";\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelShader.vsh",
    "content": "#extension GL_EXT_draw_instanced : require\n\nattribute vec4 position;\nattribute vec3 normal;\nattribute vec4 color;\nattribute vec2 texCoord;\n\nvarying vec4 colorVarying;\nvarying vec2 texCoordVarying;\n\nuniform mat4 viewProjectionModelMatrix;\nuniform mat3 normalModelMatrix;\n\nuniform vec2 trig[18];\n\nvoid main()\n{\n    float c = trig[gl_InstanceIDEXT].x;\n    float s = trig[gl_InstanceIDEXT].y;\n    \n    mat4 spanMatrix = mat4(  c, 0.0,  -s, 0.0,\n                           0.0, 1.0, 0.0, 0.0,\n                             s, 0.0,   c, 0.0,\n                           0.0, 0.0, 0.0, 1.0);\n    \n    \n    vec3 worldNormal = normalize(normalModelMatrix * mat3(spanMatrix) * normal);\n    \n    float intensity = mix(1.0, abs(worldNormal.z), 0.3);\n    \n    colorVarying = color * vec4(intensity, intensity, intensity, 1.0);\n    texCoordVarying = texCoord;\n\n    gl_Position = viewProjectionModelMatrix * spanMatrix * position;\n}\n"
  },
  {
    "path": "Revolved/RVModelSprite.h",
    "content": "//\n//  RVModelSprite.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 24.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSprite.h\"\n\n@interface RVModelSprite : RVSprite\n\n@property (nonatomic, strong) NSArray *drawnSegments;\n@property (nonatomic) GLKVector3 modelScaleVector;\n@property (nonatomic) GLKVector3 scaleVector;\n@property (nonatomic) GLKVector3 translationVector;\n@property (nonatomic) GLKVector3 extraTranslationVector;\n\n@property (nonatomic) float axisAlpha;\n@property (nonatomic) BOOL hasScissors;\n@property (nonatomic) CGRect scissorsRect;\n\n@property (nonatomic) GLKQuaternion quaternion;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelSprite.m",
    "content": "//\n//  RVModelSprite.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 24.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelSprite.h\"\n#import \"RVQuaternionAnimation.h\"\n\n@implementation RVModelSprite\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _scaleVector = GLKVector3Make(1.0f, 1.0f, 1.0f);\n        _quaternion = BaseQuaternion;\n        _modelScaleVector = GLKVector3Make(1.0f, 1.0f, 1.0f);\n    }\n    return self;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelViewController.h",
    "content": "//\n//  RVModelViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@class RVModelViewController, RVModel, RVModelSprite, RVRenderingController;\n\n@protocol RVModelViewControllerDelegate <NSObject>\n\n- (void)modelViewControllerDidRequestBack:(RVModelViewController *)controller;\n\n- (void)modelViewControllerDidRequestSharePicture:(RVModelViewController *)controller;\n- (void)modelViewControllerDidAnimateOut:(RVModelViewController *)controller;\n- (void)modelViewControllerDidAnimateIn:(RVModelViewController *)controller;\n- (void)modelViewController:(RVModelViewController *)controller didChangeModel:(RVModel *)model;\n@end\n\n\n\n@interface RVModelViewController : UIViewController\n\n@property (nonatomic, weak) id<RVModelViewControllerDelegate> delegate;\n@property (nonatomic, strong) RVRenderingController *renderingController;\n@property (nonatomic) CGFloat previewWidth;\n\n@property (nonatomic, readonly) CGRect previewFrame;\n@property (nonatomic, readonly) CGRect drawFrame;\n@property (nonatomic, readonly) GLKMatrix4 drawMatrix;\n\n\n- (void)setupModel:(RVModel *)model;\n\n- (void)tick;\n\n- (void)animateIn;\n- (void)animateOut;\n\n- (void)presentShareOptionsWithImage:(UIImage *)image;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelViewController.m",
    "content": "//\n//  RootViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVModelViewController.h\"\n#import \"RVPreviewViewController.h\"\n#import \"RVDrawViewController.h\"\n#import \"RVPictureViewController.h\"\n\n#import \"RVDrawController.h\"\n#import \"CameraController.h\"\n\n#import \"RVSpaceConverter.h\"\n#import \"RVRenderingController.h\"\n#import \"RVUserDefaults.h\"\n\n#import \"RVColorPicker.h\"\n\n#import \"RVModel.h\"\n#import \"RVModelSprite.h\"\n#import \"RVAxisSprite.h\"\n#import \"RVSegment.h\"\n\n\nstatic const float LineSize = 4.0f;\nstatic const float GuidelineDotSize = 8.0f;\nstatic const float PointSize = 64.0f;\n\n@interface RVModelViewController () <DrawControllerDelegate, RVPreviewViewControllerDelegate>\n\n\n\n@property (nonatomic, strong) RVDrawController *drawController;\n\n@property (nonatomic, strong) RVDrawViewController *drawViewController;\n@property (nonatomic, strong) RVPreviewViewController *previewViewController;\n@property (nonatomic, strong) RVPictureViewController *pictureViewController;\n\n\n\n@property (nonatomic, strong) RVSpaceConverter *converter;\n\n@property (nonatomic, strong) RVModel *model;\n\n@end\n\n@implementation RVModelViewController\n\n- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil\n{\n    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];\n    if (self) {\n        \n        _drawController = [[RVDrawController alloc] init];\n        _drawController.delegate = self;\n\n        _drawViewController = [[RVDrawViewController alloc] init];\n        _drawViewController.drawController = _drawController;\n        \n        _pictureViewController = [[RVPictureViewController alloc] init];\n        \n        _previewViewController = [[RVPreviewViewController alloc] init];\n        _previewViewController.delegate = self;\n        \n        _previewWidth = 576.0f;\n    }\n    return self;\n}\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    self.view.backgroundColor = nil;\n    \n    \n    \n    self.previewViewController.cameraController = self.renderingController.cameraController;\n    \n    [self addChildViewController:self.previewViewController];\n    [self.view addSubview:self.previewViewController.view];\n    [self.previewViewController didMoveToParentViewController:self];\n    \n    [self addChildViewController:self.drawViewController];\n    [self.view addSubview:self.drawViewController.view];\n    [self.drawViewController didMoveToParentViewController:self];\n    \n    [self addChildViewController:self.pictureViewController];\n    [self.view addSubview:self.pictureViewController.view];\n    [self.pictureViewController didMoveToParentViewController:self];\n}\n\n- (void)viewDidLayoutSubviews\n{\n    [super viewDidLayoutSubviews];\n    \n    CGRect bounds = self.view.bounds;\n    CGRect previewFrame, drawFrame;\n    CGRectDivide(bounds, &previewFrame, &drawFrame, self.previewWidth, CGRectMinXEdge);\n    \n    drawFrame.origin.x -= 30.0f;\n    drawFrame.size.width += 30.0f;\n    \n    self.previewViewController.view.frame = previewFrame;\n    self.drawViewController.view.frame = drawFrame;\n    self.pictureViewController.view.frame = bounds;\n    \n    self.converter = [[RVSpaceConverter alloc] initWithViewSize:drawFrame.size];\n    self.renderingController.pointController.pointSize = sqrtf([self.converter modelSquareDistanceForViewDistance:PointSize]);\n    self.renderingController.guidelineController.dotSize = sqrtf([self.converter modelSquareDistanceForViewDistance:GuidelineDotSize]);\n    self.renderingController.lineController.lineSize = sqrtf([self.converter modelSquareDistanceForViewDistance:LineSize]);\n    self.drawViewController.converter = self.converter;\n    \n    GLKVector2 a = [self.converter modelPointForViewPoint:CGPointZero];\n    GLKVector2 b = [self.converter modelPointForViewPoint:CGPointMake(drawFrame.size.width, drawFrame.size.height)];\n    \n    _drawFrame = drawFrame;\n    _previewFrame = previewFrame;\n    _drawMatrix = GLKMatrix4MakeOrtho(a.x, b.x, b.y, a.y, -1.0, 1.0);\n}\n\n\n- (void)setupModel:(RVModel *)model\n{\n    self.model = model;\n    self.drawController.segments = model.segments;\n    [self.previewViewController assignSegmentsToSprite:model.segments];\n    \n    [self.drawViewController addIntitialLineSpritesForSegments:model.segments.set];\n\n}\n\n#pragma mark - Ticks\n\n- (void)tick\n{\n    [self retesselateWithModel:NO];\n    [self.previewViewController tick];\n}\n\n\n\n#pragma mark -\n\n\n- (BOOL)shouldAutorotate\n{\n    return YES;\n}\n\n- (NSUInteger)supportedInterfaceOrientations\n{\n    return UIInterfaceOrientationMaskLandscape;\n}\n\n\n- (void)presentShareOptionsWithImage:(UIImage *)image\n{\n    self.pictureViewController.image = image;\n    [self.pictureViewController present];\n}\n\n\n#pragma mark - Animation\n\n- (void)animateIn\n{\n    [self retesselateWithModel:YES];\n\n    self.view.userInteractionEnabled = YES;\n\n    [CATransaction begin];\n    [CATransaction setCompletionBlock:^{\n        [self.delegate modelViewControllerDidAnimateIn:self];\n    }];\n    [self.previewViewController animateInWithDuration:0.3];\n    [self.drawViewController animateInWithDuration:0.3];\n    [CATransaction commit];\n\n    [self retesselateWithModel:NO];\n    \n    \n}\n\n- (void)animateOut\n{\n    self.view.userInteractionEnabled = NO;\n    \n    [CATransaction begin];\n    [CATransaction setCompletionBlock:^{\n        [self.delegate modelViewControllerDidAnimateOut:self];\n        [self.drawViewController clearAllSprites];\n        [self.drawController clear];\n    }];\n    [self.previewViewController animateOutWithDuration:0.3];\n    [self.drawViewController animateOutWithDuration:0.3];\n    [CATransaction commit];\n}\n\n\n#pragma mark - Tesselation\n\n\n\n- (void)retesselateWithModel:(BOOL)withModel\n{\n    if (withModel) {\n        [self.previewViewController assignSegmentsToSprite:self.model.segments];\n        [self.renderingController.modelController updateBuffersWithModelSprites:@[self.previewViewController.modelSprite]];\n        [self.renderingController.axisController updateBuffersWithLineSprites:self.drawViewController.axisSprites];\n    }\n    \n    [self.renderingController.guidelineController updateBuffersWithGuidelineDotSprites:self.drawViewController.guidelineSprites];\n    [self.renderingController.lineController updateBuffersWithLineSprites:self.drawViewController.lineSprites];\n    \n    [self.renderingController.pointController updateBuffersWithPointSprites:self.drawViewController.pointSprites];\n}\n\n\n#pragma mark - RVDrawController Delegate\n\n\n- (void)drawControllerDidSelectSegment:(RVSegment *)segment\n{\n    [self.drawViewController removeAllPointSprites];\n    [self.drawViewController selectLineSpriteForSegment:segment];\n    [self.drawViewController addPointSpritesForPoints:segment.allPoints];\n}\n\n- (void)drawControllerDidSelectEndPoint:(RVPoint *)endPoint\n{\n    \n}\n\n- (void)drawControllerDidSelectColorIndex:(NSUInteger)colorIndex\n{\n    [self.drawViewController setSelectedColorIndex:colorIndex];\n}\n\n\n- (void)drawControllerDidTryAddButReachedSegmentLimit\n{\n    [self.previewViewController flashSegmentLimitAlert];\n}\n\n- (void)drawControllerDidAddSegment:(RVSegment *)segment\n{\n    [self.drawViewController addLineSpriteForSegment:segment];\n    [self retesselateWithModel:YES];\n    \n    [self.delegate modelViewController:self didChangeModel:self.model];\n}\n\n- (void)drawControllerDidModifySegment:(RVSegment *)segment\n{\n    [self.drawViewController modifyLineSpriteForSegment:segment];\n    [self.drawViewController modifyPointSpritesForPoints:segment.allPoints];\n    \n    [self retesselateWithModel:YES];\n}\n\n- (void)drawControllerDidRemoveSegment:(RVSegment *)segment\n{\n    [self.drawViewController removeLineSpriteForSegment:segment];\n    [self.drawViewController dropPointSpritesForPoints:segment.allPoints];\n    [self retesselateWithModel:YES];\n    \n    [self.delegate modelViewController:self didChangeModel:self.model];\n}\n\n- (void)drawControllerDidRecolorSegment:(RVSegment *)segment\n{\n    [self.delegate modelViewController:self didChangeModel:self.model];\n    \n    [self.drawViewController modifyLineSpriteForSegment:segment];\n    [self.drawViewController modifyPointSpritesForPoints:segment.allPoints];\n    \n    [self retesselateWithModel:YES];\n}\n\n- (void)drawControllerDidAddGuideLine:(RVGuideline *)guideline\n{\n    [self.drawViewController addSpritesForGuideLine:guideline];\n}\n\n- (void)drawControllerDidRemoveGuideLine:(RVGuideline *)guideline\n{\n    [self.drawViewController removeSpritesForGuideLine:guideline];\n}\n\n- (void)drawControllerDidStartDraggingPoint:(RVPoint *)point\n{\n    \n}\n\n- (void)drawControllerDidDragPoint:(RVPoint *)point\n{}\n\n- (void)drawControllerDidEndDraggingPoint:(RVPoint *)point\n{\n    [self.delegate modelViewController:self didChangeModel:self.model];\n}\n\n\n#pragma mark - RVPreviewViewControllerDelegate\n\n- (void)previewControllerDidTapCameraButton:(RVPreviewViewController *)controller\n{\n    [self.delegate modelViewControllerDidRequestSharePicture:self];\n}\n\n\n- (void)previewControllerDidTapBackButton:(RVPreviewViewController *)controller\n{\n    [self.delegate modelViewControllerDidRequestBack:self];;\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4504\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" variant=\"6xAndEarlier\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment version=\"1552\" defaultVersion=\"1792\" identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3734.1\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVModelViewController\">\n            <connections>\n                <outlet property=\"view\" destination=\"7QL-DL-xp7\" id=\"78r-NC-r32\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"7QL-DL-xp7\" customClass=\"RVOpenGLView\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n            <simulatedScreenMetrics key=\"simulatedDestinationMetrics\"/>\n        </view>\n    </objects>\n</document>"
  },
  {
    "path": "Revolved/RVModelsViewController.h",
    "content": "//\n//  RVModelsViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 20.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@class RVModelsViewController, RVModelSprite, RVRenderingController, RVModel;\n\n@protocol RVModelsViewControllerDataSource <NSObject>\n\n- (NSUInteger)modelsViewControllerNumberOfModels:(RVModelsViewController *)controller;\n- (RVModel *)modelsViewController:(RVModelsViewController *)controller modelAtIndex:(NSUInteger)modelIndex;\n- (CGRect)modelsViewControllerDestinationRectForSelectedModel:(RVModelsViewController *)controller;\n\n@end\n\n\n\n@protocol RVModelsViewControllerDelegate <NSObject>\n\n- (void)modelsViewControllerDidAddModel:(RVModelsViewController *)controller;\n- (void)modelsViewController:(RVModelsViewController *)controller didSelectModelAtIndex:(NSUInteger)modelIndex;\n- (void)modelsViewController:(RVModelsViewController *)controller didDeleteModelAtIndex:(NSUInteger)modelIndex;\n- (void)modelsViewController:(RVModelsViewController *)controller didCloneModelAtIndex:(NSUInteger)modelIndex;\n- (void)modelsViewController:(RVModelsViewController *)controller didShareModelAtIndex:(NSUInteger)modelIndex;\n\n- (void)modelsViewController:(RVModelsViewController *)controller didMoveModelAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)targetIndex;\n\n- (void)modelsViewController:(RVModelsViewController *)controller didZoomInToModelAtIndex:(NSUInteger)modelIndex;\n\n- (void)modelsViewControllerDidRequestTutorial:(RVModelsViewController *)controller;\n- (void)modelsViewControllerDidZoomOut:(RVModelsViewController *)controller;\n\n@end\n\n\n@interface RVModelsViewController : UIViewController\n\n@property (nonatomic, weak) id<RVModelsViewControllerDataSource> dataSource;\n@property (nonatomic, weak) id<RVModelsViewControllerDelegate> delegate;\n@property (nonatomic, strong) RVRenderingController *renderingController;\n@property (nonatomic) CGSize previewSize;\n\n- (void)zoomOut;\n\n- (void)reloadData;\n- (void)addNewModelSpriteForModelAtIndex:(NSInteger)modelIndex;\n- (void)importModelSpriteForModelAtIndex:(NSInteger)modelIndex;\n- (void)removeModelSpriteForModel:(RVModel *)model;\n\n- (void)tick;\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelsViewController.m",
    "content": "//\n//  RVModelsViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 20.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <StoreKit/StoreKit.h>\n\n#import \"RVModelsViewController.h\"\n#import \"RVCreditsViewController.h\"\n#import \"RVTutorialViewController.h\"\n\n#import \"RVModelCell.h\"\n#import \"RVModelSprite.h\"\n\n#import \"RVModel.h\"\n#import \"RVRenderingController.h\"\n#import \"RVVectorAnimation.h\"\n#import \"DrawGestureRecognizer.h\"\n#import \"RVQuaternionAnimation.h\"\n#import \"RVFloatAnimation.h\"\n\n#import \"RVAddProgressView.h\"\n#import \"RVModelButtonsView.h\"\n#import \"RVSettingsButtonsView.h\"\n\n#import \"NSArray+Functional.h\"\n#import \"UIView+RotationAnimation.h\"\n\nstatic NSString * const CellIdentifier = @\"Cell\";\n\nstatic const CGSize CellSize = {288.0f * 1.25, 384.0f * 1.25};\nstatic const CGFloat TableInset = 100.0f;\nstatic const CGFloat OverInset = 288.0f * 1.25 / 2.0f;\n\n\nstatic const float ZOffsetActive =  0.4;\nstatic const float ZOffsetPassive = -0.5;\n\n@interface RVModelsViewController () <UITableViewDataSource, UITableViewDelegate, UIGestureRecognizerDelegate, SKStoreProductViewControllerDelegate>\n\n@property (weak, nonatomic) IBOutlet UITableView *tableView;\n@property (weak, nonatomic) IBOutlet UIView *editContainer;\n@property (weak, nonatomic) IBOutlet UIButton *editButton;\n@property (weak, nonatomic) IBOutlet UIView *startOverlay;\n\n@property (weak, nonatomic) IBOutlet RVAddProgressView *progressView;\n@property (strong, nonatomic) RVSettingsButtonsView *settingsView;\n\n@property (nonatomic, strong) RVCreditsViewController *creditsViewController;\n\n@property (nonatomic, strong) NSIndexPath *centerIndexPath;\n@property (nonatomic, strong) NSMapTable *modelToModelSpriteMap;\n\n@property (nonatomic) BOOL needsRetesellation;\n@property (nonatomic) BOOL editMode;\n\n@property (nonatomic, strong) UILongPressGestureRecognizer *dragPressRecognizer;\n@property (nonatomic, strong) UITapGestureRecognizer *tapRecognizer;\n\n@property (nonatomic) BOOL inAddButtonTapMode;\n\n@property (nonatomic, strong) NSIndexPath *draggedIndexPath;\n@property (nonatomic) CGFloat dragCenterOffset;\n@property (nonatomic) BOOL drags;\n\n@end\n\n@implementation RVModelsViewController\n\n- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil\n{\n    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];\n    if (self) {\n        _creditsViewController = [[RVCreditsViewController alloc] init];\n    }\n    return self;\n}\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    self.view.backgroundColor = nil;\n    self.modelToModelSpriteMap = [NSMapTable strongToStrongObjectsMapTable];\n    \n    self.editButton.exclusiveTouch = YES;\n    \n    [self.progressView.plus addTarget:self action:@selector(addButtonTapped:) forControlEvents:UIControlEventTouchUpInside];\n    \n    self.tableView.backgroundColor = nil;\n    self.tableView.clipsToBounds = NO;\n    self.tableView.rowHeight = CellSize.width;\n    [self.tableView registerClass:[RVModelCell class] forCellReuseIdentifier:CellIdentifier];\n    \n    self.settingsView = [[NSBundle mainBundle] loadNibNamed:@\"RVSettingsButtonsView\" owner:self options:nil][0];\n    self.settingsView.center = CGPointMake(self.view.bounds.size.width/2.0, self.view.bounds.size.height);\n    [self.settingsView.tutorialButton addTarget:self action:@selector(tutorialButtonTapped:) forControlEvents:UIControlEventTouchUpInside];\n    [self.settingsView.creditsButton addTarget:self action:@selector(creditsButtonTapped:) forControlEvents:UIControlEventTouchUpInside];\n    [self.settingsView.rateMeButton addTarget:self action:@selector(rateButtonTapped:) forControlEvents:UIControlEventTouchUpInside];\n    [self.view insertSubview:self.settingsView atIndex:0];\n    \n    self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];\n    self.tapRecognizer.delegate = self;\n    self.tapRecognizer.enabled = NO;\n    [self.view addGestureRecognizer:self.tapRecognizer];\n    \n    self.dragPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(dragPressRecognized:)];\n    self.dragPressRecognizer.delegate = self;\n    self.dragPressRecognizer.minimumPressDuration = 0.3;\n    self.dragPressRecognizer.enabled = NO;\n    [self.view addGestureRecognizer:self.dragPressRecognizer];\n    \n    \n    [self addChildViewController:self.creditsViewController];\n    [self.view addSubview:self.creditsViewController.view];\n    [self.creditsViewController didMoveToParentViewController:self];\n    \n    self.startOverlay.backgroundColor = [UIColor colorWithWhite:0.93f alpha:1.0];\n    \n    [self updateHeaderPosition];\n}\n\n- (void)viewWillAppear:(BOOL)animated\n{\n    [super viewWillAppear:animated];\n\n    [self updateSpritesPositions];\n    \n    for (RVModelSprite *modelSprite in self.modelToModelSpriteMap.objectEnumerator.allObjects) {\n        modelSprite.extraTranslationVector = GLKVector3Make(1.5f, 0.0f, 0.0f);\n    }\n}\n\n- (void)viewDidAppear:(BOOL)animated\n{\n    [super viewDidAppear:animated];\n    [self updateSpritesPositions];\n    \n    NSTimeInterval Delay = 1.1;\n    NSTimeInterval Duration = 0.5;\n    \n    for (RVModelSprite *modelSprite in self.modelToModelSpriteMap.objectEnumerator.allObjects) {\n        RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:modelSprite.extraTranslationVector toValue:GLKVector3Make(0.0f, 0.0f, 0.0f) withDuration:Duration];\n        translationAnimation.animationCurve = RVAnimationCurveQuartEaseOut;\n        translationAnimation.delay = Delay;\n        [modelSprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n    }\n    \n    [UIView animateWithDuration:Duration/2 delay:Delay options:UIViewAnimationOptionCurveEaseIn animations:^{\n        self.startOverlay.alpha = 0.0f;\n    } completion:^(BOOL finished) {\n        self.view.userInteractionEnabled = YES; // dirty hack for import animation...\n        self.startOverlay.hidden = YES;\n\n    }];\n}\n\n- (void)viewDidLayoutSubviews\n{\n    CGRect bounds = self.view.bounds;\n    \n    self.tableView.transform = CGAffineTransformIdentity;\n    self.tableView.frame = CGRectMake(0, 0, CellSize.height, bounds.size.width + 2.0f * OverInset);\n    self.tableView.contentInset = UIEdgeInsetsMake(TableInset + OverInset, 0.0f, TableInset + OverInset, 0.0f);\n    self.tableView.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds) - 10.0f);\n    self.tableView.transform = CGAffineTransformMakeRotation(-M_PI_2);\n    \n    [self updateSpritesPositions];\n    [self retesselateModels];\n}\n\n\n\n#pragma mark - Coordinate Systems\n\n- (GLKVector3)screenVectorForPoint:(CGPoint)point\n{\n    CGSize viewSize = self.view.bounds.size;\n    \n    return GLKVector3Make(point.x * 2.0f / viewSize.width - 1.0f, 1.0f - point.y * 2.0f / viewSize.height, 0.0f);\n}\n\n\n- (GLKVector3)defaultModelScaleVector\n{\n    CGSize viewSize = self.view.bounds.size;\n    \n    return GLKVector3Make(CellSize.width / viewSize.width, CellSize.height / viewSize.height, 0.3f);\n}\n\n#pragma mark - Ticks\n\n- (void)tick\n{\n    if (self.needsRetesellation) {\n        self.needsRetesellation = NO;\n        [self retesselateModels];\n    }\n    \n    if (self.drags) {\n        \n        const float StartNorm = 0.8f;\n        const float Magnitude = 20.0f;\n        \n        GLKVector3 screenPoint = [self screenVectorForPoint:[self.dragPressRecognizer locationInView:self.view]];\n        float sign = screenPoint.x > 0.0f ? 1.0f : -1.0f;\n        float speed =  Magnitude * sign * MAX(0.0f, (fabsf(screenPoint.x) - StartNorm)/(1.0f - StartNorm));\n        \n        CGPoint contentOffset = self.tableView.contentOffset;\n        contentOffset.y += speed;\n        contentOffset.y = MIN(MAX(- self.tableView.contentInset.top, contentOffset.y), self.tableView.contentSize.height + self.tableView.contentInset.bottom - self.tableView.bounds.size.height);\n        self.tableView.contentOffset = contentOffset;\n    }\n}\n\n- (void)retesselateModels\n{\n    NSArray *visibleIndexPaths = [self.tableView indexPathsForVisibleRows];\n    \n    if (self.drags && ! [visibleIndexPaths containsObject:self.draggedIndexPath]) {\n        visibleIndexPaths = [visibleIndexPaths arrayByAddingObject:self.draggedIndexPath];\n        \n    }\n    \n    NSArray *sprites = [visibleIndexPaths mapObjectsUsingBlock:^id(NSIndexPath *indexPath, NSUInteger idx) {\n        NSUInteger modelIndex = [self modelIndexForIndexPath:indexPath];\n        RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:modelIndex];\n        RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n        \n        return sprite;\n    }];\n    \n    [self.renderingController.modelController updateBuffersWithModelSprites:sprites];\n}\n\n- (void)updateSpritesPositions\n{\n    NSInteger count = [self.dataSource modelsViewControllerNumberOfModels:self];\n    for (int modelIndex = 0; modelIndex < count; modelIndex++) {\n        RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:modelIndex];\n        RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n        \n        CGPoint center = [self centerForCellAtModelIndex:modelIndex];\n        \n        sprite.translationVector = [self screenVectorForPoint:center];\n    }\n    \n    if (self.drags) {\n        NSUInteger modelIndex = [self modelIndexForIndexPath:self.draggedIndexPath];\n        RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:modelIndex];\n        RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n        \n        GLKVector3 translation = [self screenVectorForPoint:[self.dragPressRecognizer locationInView:self.view]];\n        translation.x -= self.dragCenterOffset * 2.0f/self.view.bounds.size.width;\n        translation.y = [self screenVectorForPoint:[self centerForCellAtModelIndex:0]].y;\n        \n        sprite.translationVector = translation;\n    }\n}\n\n\n\n#pragma mark - Data mapping\n\n- (void)reloadData\n{\n    NSUInteger count = [self.dataSource modelsViewControllerNumberOfModels:self];\n    \n    [self.modelToModelSpriteMap removeAllObjects];\n    for (int i = 0; i < count; i++) {\n        [self createNewSpriteForModelAtIndex:i];\n    }\n    \n    [self updateSpritesPositions];\n    [self retesselateModels];\n}\n\n- (RVModelSprite *)createNewSpriteForModelAtIndex:(NSInteger)modelIndex\n{\n    RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:modelIndex];\n    \n    RVModelSprite *sprite = [RVModelSprite new];\n    sprite.drawnSegments = model.segments.array;\n    sprite.scaleVector = [self defaultModelScaleVector];\n    sprite.translationVector = [self screenVectorForPoint:[self centerForCellAtModelIndex:modelIndex]];\n    \n    [self.modelToModelSpriteMap setObject:sprite forKey:model];\n    \n    return sprite;\n}\n\n- (void)addNewModelSpriteForModelAtIndex:(NSInteger)modelIndex;\n{\n    NSInteger count = [self.dataSource modelsViewControllerNumberOfModels:self];\n    GLKVector3 offset = GLKVector3Make(2.0f * (-CellSize.width - self.tableView.contentOffset.y - TableInset - OverInset)/self.view.bounds.size.width, 0.0f, 0.0f);\n    \n    for (int i = 0; i < count; i++) {\n        RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:i];\n        RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n        \n        sprite.extraTranslationVector = offset;\n    }\n    \n    [self createNewSpriteForModelAtIndex:modelIndex];\n    NSIndexPath *path = [self indexPathForModelIndex:modelIndex];\n    [self.tableView reloadData];\n    [self zoomInToCellAtIndexPath:path];\n}\n\n- (void)importModelSpriteForModelAtIndex:(NSInteger)modelIndex\n{\n    [self createNewSpriteForModelAtIndex:modelIndex];\n    self.tableView.contentOffset = CGPointMake(0.0f, -OverInset - TableInset);\n    [self setEditMode:NO];\n    [self.tableView insertRowsAtIndexPaths:@[[self indexPathForModelIndex:modelIndex]] withRowAnimation:UITableViewRowAnimationFade];\n    [self animateModelPositionsUsingExtra];\n    \n    [self animateImportAnimation];\n}\n\n- (void)removeModelSpriteForModel:(RVModel *)model\n{\n    [self.modelToModelSpriteMap removeObjectForKey:model];\n}\n\n#pragma mark - Header\n\n- (void)updateHeaderPosition\n{\n    self.progressView.alpha = [self currentAlphaProgress];\n    [self.progressView setProgress:[self currentAddProgress] allowingFull:self.tableView.tracking || self.inAddButtonTapMode];\n}\n\n- (float)currentAlphaProgress\n{\n    const CGFloat FullDrag = 35.0f;\n    const CGFloat Surplus = 35.0f;\n    \n    CGFloat edgePosition = -(self.tableView.contentOffset.y + TableInset + OverInset) + Surplus;\n    CGFloat percent = edgePosition/FullDrag;\n    \n    return MIN(MAX(0.0f, percent), 1.0f);\n}\n\n- (float)currentAddProgress\n{\n    const CGFloat FullDrag = 240.0f;\n    const CGFloat Surplus = 5.0f;\n    \n    CGFloat edgePosition = -(self.tableView.contentOffset.y + TableInset + OverInset + Surplus);\n    CGFloat percent = edgePosition/FullDrag;\n    \n    return MIN(MAX(0.0f, percent), 1.0f);\n}\n\n\n\n#pragma mark - Helpers\n\n- (NSUInteger)modelIndexForIndexPath:(NSIndexPath *)indexPath\n{\n    return indexPath.row;\n}\n\n- (NSIndexPath *)indexPathForModelIndex:(NSUInteger)modelIndex\n{\n    return [NSIndexPath indexPathForRow:modelIndex inSection:0];\n}\n\n- (CGPoint)centerForCellAtModelIndex:(NSInteger)modelIndex\n{\n    CGFloat offset = self.tableView.contentOffset.y + OverInset;\n    CGFloat y = self.tableView.center.y - 5.0f;\n    \n    CGPoint center = CGPointMake(-offset + (modelIndex + 0.5f)*CellSize.width, y);\n    \n    return center;\n}\n\n\n- (void)zoomInToCellAtIndexPath:(NSIndexPath *)centerPath\n{\n    const NSTimeInterval ZoomDuration = 0.3;\n    \n    self.view.userInteractionEnabled = NO;\n    \n    [UIView animateWithDuration:ZoomDuration animations:^{\n        self.view.alpha = 0.0f;\n    }];\n    \n    self.centerIndexPath = centerPath;\n    \n    NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];\n    NSInteger centerIndex = [indexPaths indexOfObject:centerPath];\n    NSAssert(centerIndex != NSNotFound, @\"\");\n    \n    CGSize viewSize = self.view.bounds.size;\n    \n    [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {\n        \n        NSUInteger modelIndex = [self modelIndexForIndexPath:indexPath];\n        RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:[self modelIndexForIndexPath:indexPath]];\n        RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n        \n        GLKVector3 currentTranslation = sprite.extraTranslationVector;\n        GLKVector3 targetTranslation = currentTranslation;\n        targetTranslation.x += 2.0f * (idx > centerIndex ? 1.0f : -1.0f);\n        \n        \n        RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:currentTranslation toValue:targetTranslation withDuration:ZoomDuration];\n        \n        if (idx == centerIndex) {\n            CGRect targetRect = [self.dataSource modelsViewControllerDestinationRectForSelectedModel:self];\n            \n            GLKVector3 currentScale = sprite.scaleVector;\n            GLKVector3 targetScale = GLKVector3Make( targetRect.size.width/viewSize.width, targetRect.size.height/viewSize.height, 1.0f);\n            targetTranslation = GLKVector3Subtract([self screenVectorForPoint:CGPointMake(CGRectGetMidX(targetRect), CGRectGetMidY(targetRect))], sprite.translationVector);\n            \n            translationAnimation.to = targetTranslation;\n            translationAnimation.completionBlock = ^{\n                [self.delegate modelsViewController:self didZoomInToModelAtIndex:modelIndex];\n            };\n            \n            RVVectorAnimation *scaleAnimation = [RVVectorAnimation vectorAnimationFromValue:currentScale toValue:targetScale withDuration:ZoomDuration];\n            [sprite addAnimation:scaleAnimation forKey:@\"scaleVector\"];\n        }\n        \n        [sprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n    }];\n}\n\n- (void)zoomOut\n{\n    const NSTimeInterval ZoomDuration = 0.3;\n    \n    [self retesselateModels];\n    GLKVector3 defaultScaleVector = [self defaultModelScaleVector];\n    \n    NSInteger centerIndex = [self modelIndexForIndexPath:self.centerIndexPath];\n    \n    [UIView animateWithDuration:ZoomDuration animations:^{\n        self.view.alpha = 1.0f;\n    }];\n    \n    NSInteger count = [self.dataSource modelsViewControllerNumberOfModels:self];\n    \n    for (NSInteger i = 0; i < count; i++) {\n        RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:i];\n        RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n        NSInteger indexDiff = (NSInteger)labs((NSInteger)i - (NSInteger)centerIndex);\n        RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:sprite.extraTranslationVector\n                                                                                      toValue:GLKVector3Make(0.0f, 0.0f, 0.0f)\n                                                                                 withDuration:ZoomDuration];\n        RVVectorAnimation *scaleAnimation = [RVVectorAnimation vectorAnimationFromValue:sprite.scaleVector toValue:defaultScaleVector withDuration:ZoomDuration];\n        translationAnimation.delay = indexDiff * 0.1;\n        \n        if (i == centerIndex) {\n            translationAnimation.completionBlock = ^{\n                self.view.userInteractionEnabled = YES;\n                [self.delegate modelsViewControllerDidZoomOut:self];\n            };\n        } else {\n            scaleAnimation.completionBlock = ^{\n                const float ScaleEps = 0.025;\n                \n                RVVectorAnimation *modelScaleAnimation = [RVVectorAnimation vectorAnimationFromValue:GLKVector3Make(1.0 - ScaleEps, 1.0 + ScaleEps, 1.0 - ScaleEps)\n                                                                                             toValue:GLKVector3Make(1.0 + ScaleEps, 1.0 - ScaleEps, 1.0 + ScaleEps)\n                                                                                        withDuration:0.8];\n                modelScaleAnimation.animationCurve = RVAnimationCurveJelly;\n                [sprite addAnimation:modelScaleAnimation forKey:@\"modelScaleVector\"];\n            };\n        }\n        \n        [sprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n        [sprite addAnimation:scaleAnimation forKey:@\"scaleVector\"];\n    }\n    \n    \n    self.centerIndexPath = nil;\n}\n\n\n#pragma mark - Button actions\n\n- (void)addButtonTapped:(UIButton *)sender\n{\n    self.view.userInteractionEnabled = NO;\n    self.inAddButtonTapMode = YES;\n    [self.tableView setContentOffset:CGPointMake(0.0, -250.0f - TableInset - OverInset) animated:YES];\n}\n\n- (IBAction)editButtonTapped:(UIButton *)sender\n{\n    [self setEditMode:!self.editMode];\n}\n\n\n- (void)creditsButtonTapped:(UIButton *)sender\n{\n    [self.creditsViewController present];\n}\n\n\n- (void)tutorialButtonTapped:(UIButton *)sender\n{\n    [self.delegate modelsViewControllerDidRequestTutorial:self];\n}\n\n- (void)rateButtonTapped:(UIButton *)sender\n{\n    NSNumber *appID = @(689658680); //Revolved\n    \n    SKStoreProductViewController *storeViewController = [[SKStoreProductViewController alloc] init];\n    [storeViewController loadProductWithParameters:@{SKStoreProductParameterITunesItemIdentifier:appID} completionBlock:nil];\n    storeViewController.delegate = self;\n    \n    [self presentViewController:storeViewController animated:YES completion:^{\n        \n        if ([storeViewController.view.subviews count] == 0) {\n            return;\n        }\n        /*\n         Flirting with the view hierarchy to plug in the review prompt\n         */\n        UIView *targetView = [storeViewController.view subviews][0];\n        \n        UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@\"ReviewBegger\"]];\n        image.frame = CGRectMake(835, 272, 170, 68);\n\n        image.transform = CGAffineTransformMakeTranslation(300.0f, 0.0f);\n        [targetView addSubview:image];\n        \n        [UIView animateWithDuration:0.5 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{\n            image.transform = CGAffineTransformIdentity;\n        } completion:^(BOOL finished) {\n            if (finished) {\n                [UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat animations:^{\n                    image.transform = CGAffineTransformMakeTranslation(11.0, 0.0);\n                } completion:NULL];\n            }\n        }];\n    }];\n}\n\n- (void)cloneButtonTapped:(UIButton *)sender\n{\n    CGPoint tableViewLocation = [sender.superview convertPoint:sender.center toView:self.tableView];\n    NSInteger modelIndex = [self modelIndexForIndexPath:[self.tableView indexPathForRowAtPoint:tableViewLocation]];\n    \n    [self animateCloneModelAtIndex:modelIndex];\n}\n\n- (void)shareButtonTapped:(UIButton *)sender\n{\n    CGPoint tableViewLocation = [sender.superview convertPoint:sender.center toView:self.tableView];\n    NSInteger modelIndex = [self modelIndexForIndexPath:[self.tableView indexPathForRowAtPoint:tableViewLocation]];\n    \n    [self.delegate modelsViewController:self didShareModelAtIndex:modelIndex];\n}\n\n- (void)confirmButtonTapped:(UIButton *)sender\n{\n    CGPoint tableViewLocation = [sender.superview convertPoint:sender.center toView:self.tableView];\n    NSInteger modelIndex = [self modelIndexForIndexPath:[self.tableView indexPathForRowAtPoint:tableViewLocation]];\n    \n    [self animateDeleteModelAtIndex:modelIndex];\n}\n\n- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController\n{\n    [self dismissViewControllerAnimated:YES completion:NULL];\n}\n\n\n#pragma mark - Animations\n\n- (void)animateDeleteModelAtIndex:(NSInteger)modelIndex\n{\n    const float Scale = 0.03f;\n    \n    NSTimeInterval Duration = 0.5;\n    \n    self.view.userInteractionEnabled = NO;\n    \n    RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:modelIndex];\n    RVModelSprite *deletedSprite = [self.modelToModelSpriteMap objectForKey:model];\n    if (deletedSprite.drawnSegments.count == 0) {\n        Duration = 0.0;\n    }\n    \n    RVVectorAnimation *scaleAnimation = [RVVectorAnimation vectorAnimationFromValue:deletedSprite.modelScaleVector\n                                                                            toValue:GLKVector3Make(Scale, Scale, Scale)\n                                                                       withDuration:Duration];\n    \n    GLKVector3 start = deletedSprite.extraTranslationVector;\n    GLKVector3 end = start;\n    end.y = -0.543;\n    RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:start\n                                                                                  toValue:end\n                                                                             withDuration:Duration];\n    translationAnimation.animationCurve = RVAnimationCurveJumpEaseIn;\n    translationAnimation.completionBlock = ^{\n        self.view.userInteractionEnabled = YES;\n        [self.modelToModelSpriteMap removeObjectForKey:model];\n        self.needsRetesellation = YES;\n        [self.delegate modelsViewController:self didDeleteModelAtIndex:modelIndex];\n        \n        [self.tableView deleteRowsAtIndexPaths:@[[self indexPathForModelIndex:modelIndex]]\n                              withRowAnimation:UITableViewRowAnimationLeft];\n        \n        \n        [self animateModelPositionsUsingExtra];\n        if ([self.dataSource modelsViewControllerNumberOfModels:self] == 0) {\n            [self setEditMode:NO];\n        }\n        \n    };\n    [deletedSprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n    \n    [deletedSprite addAnimation:scaleAnimation forKey:@\"modelScaleVector\"];\n}\n\n- (void)animateCloneModelAtIndex:(NSInteger)modelIndex\n{\n    self.view.userInteractionEnabled = NO;\n    \n    NSTimeInterval Duration = 0.3;\n    NSTimeInterval ShakeOffDuration = 0.2;\n    float Scale = 0.4;\n    \n    RVModel *sourceModel = [self.dataSource modelsViewController:self modelAtIndex:modelIndex];\n    RVModelSprite *sourceSprite = [self.modelToModelSpriteMap objectForKey:sourceModel];\n    \n    self.needsRetesellation = YES;\n    [self.delegate modelsViewController:self didCloneModelAtIndex:modelIndex];\n    NSIndexPath *path = [self indexPathForModelIndex:modelIndex];\n    [self.tableView insertRowsAtIndexPaths:@[path]\n                          withRowAnimation:UITableViewRowAnimationLeft];\n    [self animateModelPositionsUsingExtra];\n    \n    \n    RVModelSprite *clonedSprite = [self createNewSpriteForModelAtIndex:modelIndex + 1];\n    clonedSprite.extraTranslationVector = GLKVector3Make(0.0, 20.0, 1.0);\n    clonedSprite.translationVector = [self screenVectorForPoint:[self centerForCellAtModelIndex:modelIndex + 1]];\n    \n    \n    \n    GLKVector3 offsetVector = GLKVector3MultiplyScalar(GLKVector3Subtract(clonedSprite.translationVector, sourceSprite.translationVector), 0.5f);\n    \n    GLKVector3 defaultScale = [self defaultModelScaleVector];\n    GLKVector3 shrunkScale = GLKVector3MultiplyScalar(defaultScale, Scale);\n    \n    \n    \n    RVVectorAnimation *scaleAnimation = [RVVectorAnimation vectorAnimationFromValue:sourceSprite.scaleVector toValue:shrunkScale withDuration:Duration];\n    [sourceSprite addAnimation:scaleAnimation forKey:@\"scaleVector\"];\n    \n    RVQuaternionAnimation *quaternionAnimation = [RVQuaternionAnimation quaternionAnimationFromValue:sourceSprite.quaternion\n                                                                                             toValue:BaseQuaternion\n                                                                                        withDuration:ShakeOffDuration];\n    \n    [sourceSprite addAnimation:quaternionAnimation forKey:@\"quaternion\"];\n    \n    \n    RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:sourceSprite.extraTranslationVector toValue:offsetVector withDuration:Duration];\n    translationAnimation.completionBlock = ^{\n        \n        clonedSprite.extraTranslationVector = GLKVector3Negate(sourceSprite.extraTranslationVector);\n        clonedSprite.scaleVector = sourceSprite.scaleVector;\n        \n        CGRect fullRect = CGRectMake(-1.0f, -1.0f, 2.0f, 2.0f);\n        CGRect leftRect, rightRect;\n        CGRectDivide(fullRect, &leftRect, &rightRect, 1.0f + (sourceSprite.translationVector.x + sourceSprite.extraTranslationVector.x), CGRectMinXEdge);\n        \n        sourceSprite.hasScissors = YES;\n        sourceSprite.scissorsRect = leftRect;\n        clonedSprite.hasScissors = YES;\n        clonedSprite.scissorsRect = rightRect;\n        \n        RVVectorAnimation *parentTranslationAnimation = [RVVectorAnimation vectorAnimationFromValue:sourceSprite.extraTranslationVector toValue:GLKVector3Make(0, 0, 0) withDuration:Duration];\n        parentTranslationAnimation.completionBlock = ^{\n            sourceSprite.hasScissors = NO;\n            clonedSprite.hasScissors = NO;\n            [sourceSprite addAnimation:randomQuaternionAnimationForSprite(sourceSprite, -1.0f) forKey:@\"quaternion\"];\n            [clonedSprite addAnimation:randomQuaternionAnimationForSprite(clonedSprite, 1.0f) forKey:@\"quaternion\"];\n            \n            self.view.userInteractionEnabled = YES;\n        };\n        [sourceSprite addAnimation:parentTranslationAnimation forKey:@\"extraTranslationVector\"];\n        RVVectorAnimation *childTranslationAnimation = [RVVectorAnimation vectorAnimationFromValue:clonedSprite.extraTranslationVector toValue:GLKVector3Make(0, 0, 0) withDuration:Duration];\n        [clonedSprite addAnimation:childTranslationAnimation forKey:@\"extraTranslationVector\"];\n        \n        \n        RVVectorAnimation *parentScaleAnimation = [RVVectorAnimation vectorAnimationFromValue:sourceSprite.scaleVector toValue:defaultScale withDuration:Duration];\n        [sourceSprite addAnimation:parentScaleAnimation forKey:@\"scaleVector\"];\n        \n        RVVectorAnimation *childScaleAnimation = [RVVectorAnimation vectorAnimationFromValue:clonedSprite.scaleVector toValue:defaultScale withDuration:Duration];\n        [clonedSprite addAnimation:childScaleAnimation forKey:@\"scaleVector\"];\n    };\n    [sourceSprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n}\n\n- (void)animateImportAnimation\n{\n    NSTimeInterval Duration = 0.8;\n    \n    NSInteger count = [self.dataSource modelsViewControllerNumberOfModels:self];\n    \n    if (count == 0) {\n        return;\n    }\n    self.view.userInteractionEnabled = NO;\n    \n    RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:0];\n    RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n    \n    GLKVector3 start = sprite.extraTranslationVector;\n    GLKVector3 end = start;\n    end.y -= 2.0f;\n    \n    RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:end\n                                                                                  toValue:start\n                                                                             withDuration:Duration];\n    translationAnimation.completionBlock = ^{\n        self.view.userInteractionEnabled = YES;\n    };\n    [sprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n}\n\n- (void)animateModelPositionsUsingExtra\n{\n    NSTimeInterval AnimationDuration = 0.2;\n    \n    NSInteger count = [self.dataSource modelsViewControllerNumberOfModels:self];\n    \n    for (int i = 0; i < count; i++) {\n        RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:i];\n        RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n        \n        CGPoint center = [self centerForCellAtModelIndex:i];\n        GLKVector3 targetTranslation = [self screenVectorForPoint:center];\n        GLKVector3 currentTranslation = sprite.translationVector;\n        \n        GLKVector3 start = GLKVector3Subtract(currentTranslation, targetTranslation);\n        sprite.extraTranslationVector = start;\n        RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:start\n                                                                                      toValue:GLKVector3Make(0.0f, 0.0f, 0.0f)\n                                                                                 withDuration:AnimationDuration];\n        [sprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n    }\n    \n    [self updateSpritesPositions];\n}\n\n\n#pragma mark - Scroll View\n\n-(void)scrollViewDidScroll:(UIScrollView *)scrollView\n{\n    if (self.drags) {\n        [self reorderDraggedObjectIfNeeded];\n    }\n    [self updateSpritesPositions];\n    [self updateHeaderPosition];\n}\n\n\n- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset\n{\n    if (!self.editMode && scrollView.tracking && [self currentAddProgress] == 1.0f) {\n        [self.delegate modelsViewControllerDidAddModel:self];\n    }\n}\n\n- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView\n{\n    if (self.inAddButtonTapMode) {\n        self.view.userInteractionEnabled = YES;\n        self.inAddButtonTapMode = NO;\n        [self.delegate modelsViewControllerDidAddModel:self];\n    }\n}\n\n\n\n\n#pragma mark - Table View\n\n\n- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section\n{\n    return [self.dataSource modelsViewControllerNumberOfModels:self];\n}\n\n- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath\n{\n    RVModelCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];\n    [cell.buttonsView setTrashCanMode:NO animated:NO];\n    [cell.buttonsView.cloneButton addTarget:self action:@selector(cloneButtonTapped:) forControlEvents:UIControlEventTouchUpInside];\n    [cell.buttonsView.shareButton addTarget:self action:@selector(shareButtonTapped:) forControlEvents:UIControlEventTouchUpInside];\n    [cell.buttonsView.confirmTrashButton addTarget:self action:@selector(confirmButtonTapped:) forControlEvents:UIControlEventTouchUpInside];\n    \n    cell.buttonsContainerView.alpha = self.drags ? 0.0f : 1.0f;\n    \n    return cell;\n}\n\n- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath\n{\n    [self.delegate modelsViewController:self didSelectModelAtIndex:[self modelIndexForIndexPath:indexPath]];\n    [self zoomInToCellAtIndexPath:indexPath];\n}\n\n- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath\n{\n    cell.backgroundColor = nil;\n    self.needsRetesellation = YES;\n}\n\n- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath\n{\n    self.needsRetesellation = YES;\n}\n\n- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath\n{\n    return UITableViewCellEditingStyleNone;\n}\n\n- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath\n{\n    return NO;\n}\n\n#pragma mark - Editing\n\nRVQuaternionAnimation *randomQuaternionAnimationForSprite(RVModelSprite *sprite, float sign)\n{\n    float Radians = M_PI_2/20.0f;\n    float Duration = 0.08;\n    GLKVector3 axis = GLKVector3Normalize(GLKVector3Make(0.0f, 0.0f, sign * 1.0f));\n    \n    GLKQuaternion targetQuaternion = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(Radians, axis),\n                                                           BaseQuaternion);\n    RVQuaternionAnimation *quaternionAnimation = [RVQuaternionAnimation quaternionAnimationFromValue:sprite.quaternion\n                                                                                             toValue:targetQuaternion\n                                                                                        withDuration:Duration];\n    \n    quaternionAnimation.completionBlock = ^{\n        [sprite addAnimation:randomQuaternionAnimationForSprite(sprite, -sign) forKey:@\"quaternion\"];\n    };\n    \n    return quaternionAnimation;\n}\n\nRVFloatAnimation *rotationFloatAnimationForView(UIView *view, float sign)\n{\n    float Radians = M_PI_2/20.0f;\n    float Duration = 0.08;\n    \n    RVFloatAnimation *animation = [RVFloatAnimation floatAnimationFromValue:[view rv_Rotation] toValue:sign * Radians withDuration:Duration];\n    \n    animation.completionBlock = ^{\n        [view rv_addAnimation:rotationFloatAnimationForView(view, -sign) forKey:@\"rotation\"];\n    };\n    \n    return animation;\n}\n\n\nstatic double frand()\n{\n    return drand48() * 2.0 - 1.0;\n}\n\n\n- (void)setEditMode:(BOOL)editMode\n{\n    _editMode = editMode;\n    self.tableView.editing = editMode;\n    self.editButton.selected = editMode;\n    \n    \n    [UIView animateWithDuration:0.2 animations:^{\n        self.settingsView.alpha = editMode ? 0.0f : 1.0f;\n    }];\n    \n    if (editMode) {\n        for (RVModelSprite *modelSprite in self.modelToModelSpriteMap.objectEnumerator.allObjects) {\n            RVQuaternionAnimation *animation = randomQuaternionAnimationForSprite(modelSprite, 1.0f);\n            [modelSprite addAnimation:animation forKey:@\"quaternion\"];\n        }\n        \n        RVFloatAnimation *animation = rotationFloatAnimationForView(self.editButton, 1.0f);\n        [self.editButton rv_addAnimation:animation forKey:@\"rotation\"];\n        \n        \n    } else {\n        for (RVModelSprite *modelSprite in self.modelToModelSpriteMap.objectEnumerator.allObjects) {\n            RVQuaternionAnimation *animation = (RVQuaternionAnimation *)[modelSprite animationForKey:@\"quaternion\"];\n            \n            animation.completionBlock = ^{\n                RVQuaternionAnimation *quaternionAnimation = [RVQuaternionAnimation quaternionAnimationFromValue:modelSprite.quaternion\n                                                                                                         toValue:BaseQuaternion\n                                                                                                    withDuration:0.1];\n                \n                [modelSprite addAnimation:quaternionAnimation forKey:@\"quaternion\"];\n            };\n        }\n        \n        RVFloatAnimation *animation = [RVFloatAnimation floatAnimationFromValue:self.editButton.rv_Rotation toValue:0.0f withDuration:0.1];\n        [self.editButton rv_addAnimation:animation forKey:@\"rotation\"];\n    }\n    \n    self.tapRecognizer.enabled = editMode;\n    self.dragPressRecognizer.enabled = editMode;\n    self.progressView.hidden = editMode;\n}\n\n\n- (void)reorderDraggedObjectIfNeeded\n{\n    const NSTimeInterval AnimationDuration = 0.2;\n    \n    CGPoint draggedModelCenter = CGPointMake(0.0f, [self.dragPressRecognizer locationInView:self.tableView].y - self.dragCenterOffset);\n    NSIndexPath *nextIndexPath = [self.tableView indexPathForRowAtPoint:draggedModelCenter];\n    if (nextIndexPath == nil || nextIndexPath.row == self.draggedIndexPath.row) {\n        return;\n    }\n    \n    \n    NSInteger startIndex, endIndex;\n    float direction;\n    \n    if (nextIndexPath.row > self.draggedIndexPath.row) {\n        startIndex = [self modelIndexForIndexPath:self.draggedIndexPath] + 1;\n        endIndex = [self modelIndexForIndexPath:nextIndexPath];\n        direction = 1.0f;\n    } else {\n        startIndex = [self modelIndexForIndexPath:nextIndexPath];\n        endIndex = [self modelIndexForIndexPath:self.draggedIndexPath] - 1;\n        direction = -1.0f;\n    }\n    \n    for (NSInteger i = startIndex; i <= endIndex; i++) {\n        RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:i];\n        RVModelSprite *sprite = [self.modelToModelSpriteMap objectForKey:model];\n        float offset = direction * CellSize.width * 2.0f /self.view.bounds.size.width;\n        \n        RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:GLKVector3Make(offset, 0.0f, -ZOffsetPassive)\n                                                                                      toValue:GLKVector3Make(0.0f, 0.0f, -ZOffsetPassive)\n                                                                                 withDuration:AnimationDuration];\n        [sprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n    }\n    \n    \n    [self.delegate modelsViewController:self\n                    didMoveModelAtIndex:[self modelIndexForIndexPath:self.draggedIndexPath]\n                                toIndex:[self modelIndexForIndexPath:nextIndexPath]];\n    \n    self.draggedIndexPath = nextIndexPath;\n}\n\n- (void)animateDraggingStart\n{\n    NSTimeInterval AnimationDuration = 0.2;\n    \n    RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:[self modelIndexForIndexPath:self.draggedIndexPath]];\n    RVModelSprite *draggedSprite = [self.modelToModelSpriteMap objectForKey:model];\n    \n    RVQuaternionAnimation *quatAnimation = [RVQuaternionAnimation quaternionAnimationFromValue:draggedSprite.quaternion toValue:BaseQuaternion withDuration:AnimationDuration];\n    [draggedSprite addAnimation:quatAnimation forKey:@\"quaternion\"];\n    \n    \n    for (RVModelSprite *modelSprite in self.modelToModelSpriteMap.objectEnumerator.allObjects) {\n        float zOffset = (modelSprite == draggedSprite ? -ZOffsetActive : -ZOffsetPassive);\n        RVVectorAnimation *translationAnimation = [RVVectorAnimation vectorAnimationFromValue:modelSprite.extraTranslationVector\n                                                                                      toValue:GLKVector3Make(0.0, 0.0, zOffset)\n                                                                                 withDuration:AnimationDuration];\n        [modelSprite addAnimation:translationAnimation forKey:@\"extraTranslationVector\"];\n        \n        float scaleMultiplier = (modelSprite == draggedSprite ? 1.1f : 0.9f);\n        RVVectorAnimation *scaleAnimation = [RVVectorAnimation vectorAnimationFromValue:modelSprite.scaleVector\n                                                                                toValue:GLKVector3MultiplyScalar([self defaultModelScaleVector], scaleMultiplier)\n                                                                           withDuration:AnimationDuration];\n        [modelSprite addAnimation:scaleAnimation forKey:@\"scaleVector\"];\n    }\n    \n    [UIView animateWithDuration:0.2 animations:^{\n        for (RVModelCell *cell in self.tableView.visibleCells) {\n            cell.buttonsContainerView.alpha = 0.0f;\n            [cell.buttonsView setTrashCanMode:NO animated:YES];\n        }\n    }];\n    \n}\n\n- (void)animateDraggingEnd\n{\n    NSTimeInterval AnimationDuration = 0.2;\n    \n    RVModel *model = [self.dataSource modelsViewController:self modelAtIndex:[self modelIndexForIndexPath:self.draggedIndexPath]];\n    RVModelSprite *draggedSprite = [self.modelToModelSpriteMap objectForKey:model];\n    \n    RVQuaternionAnimation *animation = randomQuaternionAnimationForSprite(draggedSprite, 1.0f);\n    [draggedSprite addAnimation:animation forKey:@\"quaternion\"];\n    \n    for (RVModelSprite *modelSprite in self.modelToModelSpriteMap.objectEnumerator.allObjects) {\n        GLKVector3 startTranslation = modelSprite.extraTranslationVector;\n        if (modelSprite == draggedSprite) {\n            startTranslation.x = modelSprite.translationVector.x - [self screenVectorForPoint:[self centerForCellAtModelIndex:[self modelIndexForIndexPath:self.draggedIndexPath]]].x;\n        }\n        RVVectorAnimation *animation = [RVVectorAnimation vectorAnimationFromValue:startTranslation toValue:GLKVector3Make(0.0, 0.0, 0.0f) withDuration:AnimationDuration];\n        [modelSprite addAnimation:animation forKey:@\"extraTranslationVector\"];\n        \n        RVVectorAnimation *scaleAnimation = [RVVectorAnimation vectorAnimationFromValue:modelSprite.scaleVector\n                                                                                toValue:[self defaultModelScaleVector]\n                                                                           withDuration:AnimationDuration];\n        [modelSprite addAnimation:scaleAnimation forKey:@\"scaleVector\"];\n    }\n    \n    [UIView animateWithDuration:0.2 animations:^{\n        for (RVModelCell *cell in self.tableView.visibleCells) {\n            cell.buttonsContainerView.alpha = 1.0f;\n        }\n    }];\n}\n\n#pragma mark - Gesture Recognizers\n\n- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch\n{\n    if (gestureRecognizer == _dragPressRecognizer && (gestureRecognizer.numberOfTouches >= 1 || [touch.view isKindOfClass:[UIButton class]])) {\n        return NO;\n    }\n    \n    return YES;\n}\n\n- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer\n{\n    if (gestureRecognizer == self.dragPressRecognizer && ![self.tableView pointInside:[gestureRecognizer locationInView:self.tableView] withEvent:nil]) {\n        return NO;\n    }\n    \n    if (gestureRecognizer == self.tapRecognizer  && [self.tableView pointInside:[gestureRecognizer locationInView:self.tableView] withEvent:nil]) {\n        return NO;\n    }\n    \n    return YES;\n}\n\n- (void)tap:(UITapGestureRecognizer *)sender\n{\n    self.editMode = NO;\n}\n\n\n- (void)dragPressRecognized:(UILongPressGestureRecognizer *)sender\n{\n    CGPoint location = [sender locationInView:self.view];\n    \n    switch (sender.state) {\n        case UIGestureRecognizerStateBegan:\n            self.tableView.panGestureRecognizer.enabled = NO;\n            self.drags = YES;\n            self.draggedIndexPath = [self.tableView indexPathForRowAtPoint:[self.view convertPoint:location toView:self.tableView]];\n            self.dragCenterOffset = location.x - [self centerForCellAtModelIndex:[self modelIndexForIndexPath:self.draggedIndexPath]].x;\n            [self animateDraggingStart];\n            break;\n        case UIGestureRecognizerStateChanged:\n            [self reorderDraggedObjectIfNeeded];\n            [self updateSpritesPositions];\n            break;\n        case UIGestureRecognizerStateEnded:\n        case UIGestureRecognizerStateCancelled:\n            [self animateDraggingEnd];\n            self.tableView.panGestureRecognizer.enabled = YES;\n            self.drags = NO;\n            self.draggedIndexPath = nil;\n            [self updateSpritesPositions];\n            break;\n        default:\n            break;\n    }\n    \n    \n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVModelsViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"5023\" systemVersion=\"13B42\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <deployment defaultVersion=\"1792\" identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3733\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVModelsViewController\">\n            <connections>\n                <outlet property=\"editButton\" destination=\"O5O-qL-uTd\" id=\"XVS-9w-VtY\"/>\n                <outlet property=\"editContainer\" destination=\"dgt-lc-Ihf\" id=\"0hQ-I3-z2r\"/>\n                <outlet property=\"progressView\" destination=\"Pgy-uE-8aC\" id=\"5Ti-oY-jWa\"/>\n                <outlet property=\"startOverlay\" destination=\"JEm-kc-NC5\" id=\"3j5-2x-Nxk\"/>\n                <outlet property=\"tableView\" destination=\"PQA-Ik-Zww\" id=\"AQK-Xb-q20\"/>\n                <outlet property=\"view\" destination=\"2\" id=\"3\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" id=\"2\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n            <subviews>\n                <tableView clipsSubviews=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" showsHorizontalScrollIndicator=\"NO\" showsVerticalScrollIndicator=\"NO\" style=\"plain\" separatorStyle=\"none\" rowHeight=\"44\" sectionHeaderHeight=\"22\" sectionFooterHeight=\"22\" id=\"PQA-Ik-Zww\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"144\" width=\"1024\" height=\"480\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                    <color key=\"sectionIndexTrackingBackgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                    <connections>\n                        <outlet property=\"dataSource\" destination=\"-1\" id=\"rQ7-SW-rgK\"/>\n                        <outlet property=\"delegate\" destination=\"-1\" id=\"SXq-Ev-B4M\"/>\n                    </connections>\n                </tableView>\n                <view contentMode=\"scaleToFill\" id=\"Pgy-uE-8aC\" customClass=\"RVAddProgressView\">\n                    <rect key=\"frame\" x=\"25\" y=\"359\" width=\"50\" height=\"50\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                    <color key=\"backgroundColor\" red=\"1\" green=\"0.054199093339999997\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                </view>\n                <view contentMode=\"scaleToFill\" id=\"dgt-lc-Ihf\">\n                    <rect key=\"frame\" x=\"477\" y=\"603\" width=\"70\" height=\"70\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <subviews>\n                        <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"O5O-qL-uTd\">\n                            <rect key=\"frame\" x=\"10\" y=\"10\" width=\"50\" height=\"50\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                            <state key=\"normal\" image=\"Dots\"/>\n                            <state key=\"selected\" image=\"DotsSelected\"/>\n                            <connections>\n                                <action selector=\"editButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"24L-Tc-A8d\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                </view>\n                <view contentMode=\"scaleToFill\" id=\"JEm-kc-NC5\" userLabel=\"StartOverlay\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                </view>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"Logo\" id=\"nVv-mt-7bZ\">\n                    <rect key=\"frame\" x=\"362\" y=\"64\" width=\"300\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n            <simulatedScreenMetrics key=\"simulatedDestinationMetrics\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"Dots\" width=\"44\" height=\"26\"/>\n        <image name=\"DotsSelected\" width=\"44\" height=\"26\"/>\n        <image name=\"Logo\" width=\"300\" height=\"54\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Revolved/RVOBJExporter.h",
    "content": "//\n//  RVOBJExporter.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 16.11.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVExporter.h\"\n\n@interface RVOBJExporter : RVExporter\n\n@end\n"
  },
  {
    "path": "Revolved/RVOBJExporter.m",
    "content": "//\n//  RVOBJExporter.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 16.11.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVOBJExporter.h\"\n#import \"RVModel.h\"\n#import \"RVSegment.h\"\n\n#import \"Vertex.h\"\n#import \"Constants.h\"\n\n@implementation RVOBJExporter\n\n\n- (void)appendModel:(RVModel *)model toHandle:(NSFileHandle *)handle\n{\n    NSMutableData *data = [NSMutableData dataWithCapacity:1 << 20];\n    \n    [data appendData:[@\"#Generated in Revolved\\no RevolvedModel\\ng RevolvedModel\\n\" dataUsingEncoding:NSUTF8StringEncoding]];\n    [data appendData:[@\"mtllib RevolvedMaterials.mtl\\n\" dataUsingEncoding:NSUTF8StringEncoding]];\n    \n    GLKMatrix4 rotationMatrix = GLKMatrix4MakeRotation(2.0 * M_PI / (Spans * StripesPerSpan), 0.0, 1.0, 0.0);\n    \n    static char buffer[2048];\n    int len = 0;\n    \n    for (RVSegment *segment in model.segments) {\n        \n        NSUInteger tesselationSegments = [segment modelTesselationSegments];\n        SegmentTesselator tessalator = segment.tesselator;\n        \n        for (int seg = 0; seg < tesselationSegments + 1; seg++) {\n            \n            SegmentTesselation tess = tessalator((double)seg/(double)tesselationSegments);\n            \n            GLKVector3 a = GLKVector3Make(tess.p.x, tess.p.y, 0.0);\n            \n            for (int stripe = 0; stripe < Spans * StripesPerSpan; stripe++) {\n                \n                len = snprintf(buffer, sizeof(buffer), \"v %f %f %f\\n\", a.x, a.y, a.z);\n                [data appendBytes:buffer length:len];\n                a = GLKMatrix4MultiplyVector3(rotationMatrix, a);\n            }\n        }\n        \n    }\n    \n    [data appendData:[@\"\\ns 1\\n\" dataUsingEncoding:NSUTF8StringEncoding]];\n\n\n    const unsigned int VerticesInSpan = StripesPerSpan * Spans;\n\n    unsigned int vertices = 1; // in OBJ vertices start from 1\n    for (RVSegment *segment in model.segments) {\n        \n        len = snprintf(buffer, sizeof(buffer), \"usemtl mat%d\\n\", (int)segment.colorIndex);\n        [data appendBytes:buffer length:len];\n        \n        \n        NSUInteger tesselationSegments = [segment modelTesselationSegments];\n        \n        for (int seg = 0; seg < tesselationSegments; seg++) {\n            for (int stripe = 0; stripe < Spans * StripesPerSpan - 1; stripe++) {\n                \n                len = snprintf(buffer, sizeof(buffer), \"f %u %u %u\\n\", vertices + 0, vertices + VerticesInSpan, vertices + 1);\n                [data appendBytes:buffer length:len];\n\n                len = snprintf(buffer, sizeof(buffer), \"f %u %u %u\\n\", vertices + VerticesInSpan, vertices + VerticesInSpan + 1, vertices + 1);\n                [data appendBytes:buffer length:len];\n                \n                vertices++;\n            }\n            len = snprintf(buffer, sizeof(buffer), \"f %u %u %u\\n\", vertices + 0, vertices + VerticesInSpan, vertices + 1 - VerticesInSpan);\n            [data appendBytes:buffer length:len];\n\n            len = snprintf(buffer, sizeof(buffer), \"f %u %u %u\\n\", vertices + VerticesInSpan, vertices + 1, vertices + 1 - VerticesInSpan);\n            [data appendBytes:buffer length:len];\n\n            vertices++;\n        }\n        \n        vertices += VerticesInSpan;\n    }\n    \n    [handle writeData:data];\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVOpenGLView.h",
    "content": "//\n//  RVOpenGLView.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 21.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n/*\n I'm not using GLKView because its -snapshot method is slow and there are faster\n means of obtaining the image.\n */\n\n@interface RVOpenGLView : UIView\n\n@property (nonatomic, strong) EAGLContext *context;\n\n@property (nonatomic, readonly) GLint drawableWidth;\n@property (nonatomic, readonly) GLint drawableHeight;\n\n- (void)presentWithRenderingBlock:(void (^)(void))renderingBlock;\n- (UIImage *)snapshotWithRenderingBlock:(void (^)(void))renderingBlock;\n\n@end\n"
  },
  {
    "path": "Revolved/RVOpenGLView.m",
    "content": "//\n//  RVOpenGLView.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 21.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVOpenGLView.h\"\n\n@interface RVOpenGLView()\n@property (nonatomic) GLuint colorRenderbuffer;\n@property (nonatomic) GLuint resolveFramebuffer;\n\n@property (nonatomic) GLuint sampleFramebuffer;\n@property (nonatomic) GLuint sampleColorRenderbuffer;\n@property (nonatomic) GLuint sampleDepthRenderbuffer;\n\n@end\n\n@implementation RVOpenGLView\n\n+ (Class)layerClass\n{\n    return [CAEAGLLayer class];\n}\n\n- (id)initWithFrame:(CGRect)frame\n{\n    self = [super initWithFrame:frame];\n    if (self) {\n        [self commonInit];\n    }\n    return self;\n}\n\n- (id)initWithCoder:(NSCoder *)aDecoder\n{\n    self = [super initWithCoder:aDecoder];\n    if (self) {\n        [self commonInit];\n    }\n    return self;\n}\n\n- (void)dealloc\n{\n    [self destroyRenderBuffers];\n}\n\n- (void)commonInit\n{\n    self.layer.opaque = YES;\n    self.layer.contentsScale = [[UIScreen mainScreen] scale];\n}\n\n- (void)setContext:(EAGLContext *)context\n{\n    _context = context;\n    \n    [self createRenderBuffers];\n}\n\n- (void)destroyRenderBuffers\n{\n    if (_resolveFramebuffer) {\n        glDeleteFramebuffers(1, &_resolveFramebuffer);\n        _resolveFramebuffer = 0;\n    }\n    \n    if (_colorRenderbuffer) {\n        glDeleteRenderbuffers(1, &_colorRenderbuffer);\n        _colorRenderbuffer = 0;\n    }\n    \n    \n    \n    if (_sampleDepthRenderbuffer) {\n        glDeleteFramebuffers(1, &_sampleDepthRenderbuffer);\n        _sampleDepthRenderbuffer = 0;\n    }\n    \n    if (_sampleColorRenderbuffer) {\n        glDeleteRenderbuffers(1, &_sampleColorRenderbuffer);\n        _sampleColorRenderbuffer = 0;\n    }\n    \n    if (_sampleFramebuffer) {\n        glDeleteRenderbuffers(1, &_sampleFramebuffer);\n        _sampleFramebuffer = 0;\n    }\n    \n}\n\n- (void)createRenderBuffers\n{\n    glGenRenderbuffers(1, &_colorRenderbuffer);\n    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer);\n    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];\n\n    glGenFramebuffers(1, &_resolveFramebuffer);\n    glBindFramebuffer(GL_FRAMEBUFFER, _resolveFramebuffer);\n    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderbuffer);\n    \n    \n    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_drawableWidth);\n    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_drawableHeight);\n    \n    \n    glGenFramebuffers(1, &_sampleFramebuffer);\n    glBindFramebuffer(GL_FRAMEBUFFER, _sampleFramebuffer);\n\n    glGenRenderbuffers(1, &_sampleColorRenderbuffer);\n    glBindRenderbuffer(GL_RENDERBUFFER, _sampleColorRenderbuffer);\n    glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, _drawableWidth, _drawableHeight);\n    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _sampleColorRenderbuffer);\n    \n    glGenRenderbuffers(1, &_sampleDepthRenderbuffer);\n    glBindRenderbuffer(GL_RENDERBUFFER, _sampleDepthRenderbuffer);\n    glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT24_OES, _drawableWidth, _drawableHeight);\n    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _sampleDepthRenderbuffer);\n}\n\n- (void)presentWithRenderingBlock:(void (^)(void))renderingBlock\n{\n    glBindFramebuffer(GL_FRAMEBUFFER, _sampleFramebuffer);\n\n    renderingBlock();\n\n    const GLenum depthDiscard  = GL_DEPTH_ATTACHMENT;\n    glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &depthDiscard);\n    \n    glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, _sampleFramebuffer);\n    glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, _resolveFramebuffer);\n\n    glResolveMultisampleFramebufferAPPLE();\n    \n    const GLenum discards[]  = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT};\n    glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, discards);\n    \n    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer);\n    [_context presentRenderbuffer:GL_RENDERBUFFER];\n}\n\nvoid dataProviderReleaseDataCallback(void *info, const void *data, size_t size)\n{\n    free((void *)data);\n}\n\n\n/*\n https://github.com/BradLarson/GPUImage/blob/8986763eaf1061d150356c3ccfaf85bba679ad89/framework/Source/GPUImageFilter.m\n */\n\n- (UIImage *)snapshotWithRenderingBlock:(void (^)(void))renderingBlock\n{\n    glBindFramebuffer(GL_FRAMEBUFFER, _sampleFramebuffer);\n\n    renderingBlock();\n    \n    \n    GLuint dataFramebuffer;\n    glGenFramebuffers(1, &dataFramebuffer);\n    glBindFramebuffer(GL_FRAMEBUFFER, dataFramebuffer);\n    \n    \n    CVOpenGLESTextureCacheRef rawDataTextureCache;\n    CVReturn error = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, [EAGLContext currentContext], NULL, &rawDataTextureCache);\n    \n    if (error) {\n        NSAssert(NO, @\"Error at CVOpenGLESTextureCacheCreate %d\", error);\n    }\n    \n    // Code originally sourced from http://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/\n    \n    CFDictionaryRef empty; // empty value for attr value.\n    CFMutableDictionaryRef attrs;\n    empty = CFDictionaryCreate(kCFAllocatorDefault, // our empty IOSurface properties dictionary\n                               NULL,\n                               NULL,\n                               0,\n                               &kCFTypeDictionaryKeyCallBacks,\n                               &kCFTypeDictionaryValueCallBacks);\n    attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,\n                                      1,\n                                      &kCFTypeDictionaryKeyCallBacks,\n                                      &kCFTypeDictionaryValueCallBacks);\n    \n    CFDictionarySetValue(attrs,\n                         kCVPixelBufferIOSurfacePropertiesKey,\n                         empty);\n    \n    CVPixelBufferRef renderTarget;\n    CVPixelBufferCreate(kCFAllocatorDefault,\n                        _drawableWidth,\n                        _drawableHeight,\n                        kCVPixelFormatType_32BGRA,\n                        attrs,\n                        &renderTarget);\n    \n    CVOpenGLESTextureRef renderTexture;\n    CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault,\n                                                  rawDataTextureCache, renderTarget,\n                                                  NULL, // texture attributes\n                                                  GL_TEXTURE_2D,\n                                                  GL_RGBA, // opengl format\n                                                  _drawableWidth,\n                                                  _drawableHeight,\n                                                  GL_BGRA, // native iOS format\n                                                  GL_UNSIGNED_BYTE,\n                                                  0,\n                                                  &renderTexture);\n    CFRelease(attrs);\n    CFRelease(empty);\n    glActiveTexture(GL_TEXTURE2);\n\n    glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture));\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    \n    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0);\n\n    \n    glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, dataFramebuffer);\n    glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, _sampleFramebuffer);\n    glResolveMultisampleFramebufferAPPLE();\n    \n    glFinish();\n    \n    \n    \n    CVPixelBufferLockBaseAddress(renderTarget, 0);\n    GLubyte *_rawBytesForImage = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);\n    \n    NSUInteger paddedWidthOfImage = CVPixelBufferGetBytesPerRow(renderTarget) / 4;\n    NSUInteger paddedBytesForImage = paddedWidthOfImage * _drawableHeight * 4;\n    \n    void *copiedData = malloc(paddedBytesForImage);\n    memcpy(copiedData, _rawBytesForImage, paddedBytesForImage);\n\n    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, copiedData, paddedBytesForImage, dataProviderReleaseDataCallback);\n    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();\n    \n    CGImageRef cgImageFromBytes = CGImageCreate(_drawableWidth, _drawableHeight, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);\n    \n    CVPixelBufferUnlockBaseAddress(renderTarget, 0);\n    \n    UIImage *image = [UIImage imageWithCGImage:cgImageFromBytes];\n    \n    CGImageRelease(cgImageFromBytes);\n    CGDataProviderRelease(dataProvider);\n    CGColorSpaceRelease(colorSpace);\n    \n    \n    if (renderTexture) {\n        CFRelease(renderTexture);\n        renderTexture = NULL;\n    }\n    \n    if (dataFramebuffer) {\n        glDeleteFramebuffers(1, &dataFramebuffer);\n        dataFramebuffer = 0;\n    }\n    \n    if (rawDataTextureCache) {\n        CVOpenGLESTextureCacheFlush(rawDataTextureCache, 0);\n        CFRelease(rawDataTextureCache);\n        rawDataTextureCache = 0;\n    }\n    \n    if (renderTarget) {\n        CVPixelBufferRelease(renderTarget);\n        renderTarget = 0;\n    }\n    \n\n    \n    return image;\n\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVPassForwardView.h",
    "content": "//\n//  RVPassForwardView.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVPassForwardView : UIView\n\n@property (nonatomic, weak) UIView *forwardView;\n\n@end\n"
  },
  {
    "path": "Revolved/RVPassForwardView.m",
    "content": "//\n//  RVPassForwardView.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPassForwardView.h\"\n\n@implementation RVPassForwardView\n\n- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event\n{\n    UIView *target = [super hitTest:point withEvent:event];\n    \n    if (target == self) {\n        return self.forwardView;\n    }\n    \n    return target;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVPictureViewController.h",
    "content": "//\n//  RVPictureViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 20.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVPictureViewController : UIViewController\n\n@property (nonatomic, strong) UIImage *image;\n\n- (void)present;\n\n@end\n"
  },
  {
    "path": "Revolved/RVPictureViewController.m",
    "content": "//\n//  RVPictureViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 20.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <MessageUI/MessageUI.h>\n#import \"MFMailComposeViewController+SendIfPossible.h\"\n#import <Social/Social.h>\n#import <AssetsLibrary/AssetsLibrary.h>\n\n#import \"RVPictureViewController.h\"\n\n\nstatic NSString * const ShareText = @\"Check out what I've created in Revolved app! \\nhttp://bit.ly/Rvlvd\";\n\n\n@interface RVPictureViewController () <MFMailComposeViewControllerDelegate>\n@property (weak, nonatomic) IBOutlet UIControl *backgroundView;\n@property (weak, nonatomic) IBOutlet UIView *containerView;\n@property (weak, nonatomic) IBOutlet UIImageView *imageView;\n@property (weak, nonatomic) IBOutlet UIView *separator;\n@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *buttons;\n\n@end\n\n@implementation RVPictureViewController\n\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    self.view.hidden = YES;\n}\n\n- (void)present\n{\n    const NSTimeInterval BackgroundDuration = 0.2;\n    const NSTimeInterval SlideDelay = 0.1;\n    const NSTimeInterval SlideDuration = 0.5;\n    \n    self.view.hidden = NO;\n    self.backgroundView.alpha = 0.0f;\n    self.backgroundView.backgroundColor = [UIColor rv_dimColor];\n    self.containerView.transform = CGAffineTransformMakeTranslation(0.0, self.view.bounds.size.height);\n    self.imageView.image = self.image;\n    self.separator.backgroundColor = [UIColor rv_tintColor];\n    \n    for (UIButton *button in self.buttons) {\n        button.exclusiveTouch = YES;\n    }\n    \n    [UIView animateWithDuration:BackgroundDuration animations:^{\n        self.backgroundView.alpha = 1.0f;\n    }];\n    \n    [UIView animateWithDuration:SlideDuration delay:SlideDelay usingSpringWithDamping:0.85 initialSpringVelocity:0.0 options:0 animations:^{\n        self.containerView.transform = CGAffineTransformIdentity;\n    } completion:NULL];\n}\n\n- (void)dismissWithSuccess:(BOOL)success\n{\n    const NSTimeInterval BackgroundDuration = 0.2;\n    const NSTimeInterval BackgroundDelay = 0.3;\n    const NSTimeInterval SlideDuration = 0.5;\n    \n    [UIView animateWithDuration:BackgroundDuration delay:BackgroundDelay options:0 animations:^{\n        self.backgroundView.alpha = 0.0f;\n    } completion:^(BOOL finished) {\n        self.view.hidden = YES;\n        self.imageView.image = nil;\n        self.image = nil;\n    }];\n    \n    CGFloat offset = (success ? -1.0 : 1.0) * self.view.bounds.size.height;\n    \n    [UIView animateWithDuration:SlideDuration delay:0.0 usingSpringWithDamping:1.0 initialSpringVelocity:-5.0 options:0 animations:^{\n        self.containerView.transform = CGAffineTransformMakeTranslation(0.0, offset);\n    } completion:NULL];\n}\n\n- (void)setButtonsEnabled:(BOOL)enabled\n{\n    \n}\n\n- (IBAction)twitterButtonTapped:(UIButton *)sender\n{\n    SLComposeViewController *composeController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];\n    [composeController setInitialText:ShareText];\n    [composeController addImage:self.image];\n    [composeController setCompletionHandler:^(SLComposeViewControllerResult result){\n        if (result == SLComposeViewControllerResultDone) {\n            [self dismissWithSuccess:YES];\n        }\n    }];\n    \n    [self presentViewController:composeController animated:YES completion:NULL];\n}\n\n- (IBAction)facebookButtonTapped:(UIButton *)sender\n{\n    SLComposeViewController *composeController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];\n    [composeController setInitialText:ShareText];\n    [composeController addImage:self.image];\n    [composeController setCompletionHandler:^(SLComposeViewControllerResult result){\n        if (result == SLComposeViewControllerResultDone) {\n            [self dismissWithSuccess:YES];\n        }\n    }];\n    \n    [self presentViewController:composeController animated:YES completion:NULL];\n}\n\n- (IBAction)emailButtonTapped:(UIButton *)sender\n{\n    if ([MFMailComposeViewController rv_canSendEmailIfNotShowAlert]) {\n        MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];\n        mailer.mailComposeDelegate = self;\n        \n        [mailer setSubject:@\"Picture from Revolved app\"];\n        [mailer setMessageBody:ShareText isHTML:NO];\n        [mailer addAttachmentData:UIImagePNGRepresentation(self.image)\n                         mimeType:@\"image/png\" fileName:@\"model picture.png\"];\n        [self presentViewController:mailer animated:YES completion:^{}];\n    }\n}\n\n- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error\n{\n    if (result == MFMailComposeResultFailed) {\n        [MFMailComposeViewController rv_showDefaultFailAlertWithError:error];\n    } else {\n        [self dismissViewControllerAnimated:YES completion:^{\n            if (result == MFMailComposeResultSaved || result == MFMailComposeResultSent) {\n                [self dismissWithSuccess:YES];\n            }\n        }];\n    }\n}\n\n- (IBAction)cameraRollButtonTapped:(UIButton *)sender\n{\n    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];\n    [library writeImageToSavedPhotosAlbum:self.image.CGImage\n                              orientation:(ALAssetOrientation)self.image.imageOrientation\n                          completionBlock:^(NSURL *assetURL, NSError *error) {\n                              if (!error) {\n                                  [self dismissWithSuccess:YES];\n                              }\n                          }];\n}\n\n- (IBAction)backgroundTouchedUp:(UIControl *)sender\n{\n    [self dismissWithSuccess:NO];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVPictureViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <deployment defaultVersion=\"1792\" identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVPictureViewController\">\n            <connections>\n                <outlet property=\"backgroundView\" destination=\"Kq9-Us-hVb\" id=\"Ox9-hn-Z4n\"/>\n                <outlet property=\"containerView\" destination=\"NzG-bT-hOZ\" id=\"4hp-07-mwp\"/>\n                <outlet property=\"imageView\" destination=\"bce-B8-BoT\" id=\"bBo-QF-Sfe\"/>\n                <outlet property=\"separator\" destination=\"3Mo-WW-uRg\" id=\"91t-Pl-V4C\"/>\n                <outlet property=\"view\" destination=\"2\" id=\"3\"/>\n                <outletCollection property=\"buttons\" destination=\"Atp-Oj-fgZ\" id=\"Hoc-04-rqQ\"/>\n                <outletCollection property=\"buttons\" destination=\"3HS-wv-8Hl\" id=\"PEI-E9-g07\"/>\n                <outletCollection property=\"buttons\" destination=\"ON7-fh-Ccz\" id=\"pdZ-hs-Vzr\"/>\n                <outletCollection property=\"buttons\" destination=\"d0h-FJ-7an\" id=\"bK0-Kd-pAT\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" id=\"2\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"Kq9-Us-hVb\" userLabel=\"Background\" customClass=\"UIControl\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                    <subviews>\n                        <view contentMode=\"scaleToFill\" id=\"NzG-bT-hOZ\" userLabel=\"Container\">\n                            <rect key=\"frame\" x=\"260\" y=\"19\" width=\"504\" height=\"726\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                            <subviews>\n                                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" id=\"bce-B8-BoT\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"504\" height=\"672\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                </imageView>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"Atp-Oj-fgZ\">\n                                    <rect key=\"frame\" x=\"107\" y=\"675\" width=\"50\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"Twitter\"/>\n                                    <connections>\n                                        <action selector=\"twitterButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"RvY-m2-6MN\"/>\n                                    </connections>\n                                </button>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"3HS-wv-8Hl\">\n                                    <rect key=\"frame\" x=\"187\" y=\"675\" width=\"50\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"Facebook\"/>\n                                    <connections>\n                                        <action selector=\"facebookButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"pDe-xf-TEe\"/>\n                                    </connections>\n                                </button>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"d0h-FJ-7an\">\n                                    <rect key=\"frame\" x=\"267\" y=\"675\" width=\"50\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"MailButton\"/>\n                                    <connections>\n                                        <action selector=\"emailButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"wWm-75-bQc\"/>\n                                    </connections>\n                                </button>\n                                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"ON7-fh-Ccz\">\n                                    <rect key=\"frame\" x=\"347\" y=\"673\" width=\"50\" height=\"50\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"boldSystem\" size=\"button\"/>\n                                    <state key=\"normal\" image=\"Save\"/>\n                                    <connections>\n                                        <action selector=\"cameraRollButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"bbB-Hf-Q1p\"/>\n                                    </connections>\n                                </button>\n                                <view contentMode=\"scaleToFill\" id=\"3Mo-WW-uRg\" userLabel=\"Separator\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"672\" width=\"504\" height=\"1\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMaxY=\"YES\"/>\n                                    <color key=\"backgroundColor\" red=\"0.4797979798\" green=\"0.4797979798\" blue=\"0.4797979798\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                </view>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"0.93792769160583944\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        </view>\n                    </subviews>\n                    <color key=\"backgroundColor\" white=\"0.14999999999999999\" alpha=\"0.80000000000000004\" colorSpace=\"calibratedWhite\"/>\n                    <connections>\n                        <action selector=\"backgroundTouchedUp:\" destination=\"-1\" eventType=\"touchUpOutside\" id=\"6Ib-sC-MMP\"/>\n                        <action selector=\"backgroundTouchedUp:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"wtp-L2-fBL\"/>\n                    </connections>\n                </view>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n            <simulatedStatusBarMetrics key=\"simulatedStatusBarMetrics\" statusBarStyle=\"blackOpaque\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"Facebook\" width=\"30\" height=\"30\"/>\n        <image name=\"MailButton\" width=\"34\" height=\"24\"/>\n        <image name=\"Save\" width=\"24\" height=\"32\"/>\n        <image name=\"Twitter\" width=\"38\" height=\"32\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVPoint.h",
    "content": "//\n//  RVPoint.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"SegmentEnd.h\"\n\n@class RVSegment;\n\ntypedef NS_ENUM(NSInteger, PointType) {\n    PointTypeEnd = 1,\n    PointTypeControl,\n    PointTypeAnchor\n};\n\n\n\n@interface RVPoint : NSObject\n\n@property (nonatomic, readonly, weak) RVSegment *segment;\n@property (nonatomic, readonly) SegmentEnd segmentEnd;\n@property (nonatomic, readonly) PointType type;\n\n@property (nonatomic) GLKVector2 position;\n\n- (id)initWithSegment:(RVSegment *)segment segmentEnd:(SegmentEnd)segmentEnd;\n\n- (float)hitSquareDistance:(GLKVector2)point;\n\n\n@end\n\n"
  },
  {
    "path": "Revolved/RVPoint.m",
    "content": "//\n//  RVPoint.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPoint.h\"\n#import \"Geometry.h\"\n\n@implementation RVPoint\n\n- (id)initWithSegment:(RVSegment *)segment segmentEnd:(SegmentEnd)segmentEnd;\n{\n    self = [super init];\n    if (self) {\n        _segment = segment;\n        _segmentEnd = segmentEnd;\n    }\n    return self;\n}\n\n- (PointType)type\n{\n    assert(NO);\n    return PointTypeEnd;\n}\n\n- (float)hitSquareDistance:(GLKVector2)point\n{\n    return GLKVector2DistanceSq(_position, point);\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVPointMeshController.h",
    "content": "//\n//  RVPointMeshController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVMeshController.h\"\n\n@interface RVPointMeshController : RVMeshController\n\n@property (nonatomic) float pointSize;\n\n- (void)updateBuffersWithPointSprites:(NSArray *)pointSprites;\n\n@end\n"
  },
  {
    "path": "Revolved/RVPointMeshController.m",
    "content": "//\n//  RVPointMeshController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPointMeshController.h\"\n#import \"RVMeshController_Private.h\"\n#import \"BCShader.h\"\n\n#import \"RVPointSprite.h\"\n#import \"PointVertex.h\"\n\nstatic const NSUInteger VertexLimit = 480;\nstatic const NSUInteger IndexLimit = VertexLimit * 2;\n\n\nstatic GLKVector2 PointTexTypeOffset[] = {\n    [PointTypeEnd]     = {0.0, 0.0},\n    [PointTypeControl] = {0.5, 0.0},\n    [PointTypeAnchor]  = {0.5, 0.5},\n};\n\nstatic GLKVector2 PointTexEndPos[2][4] = {\n    [SegmentEndFirst][0] = {0.5, 0.5},\n    [SegmentEndFirst][1] = {0.0, 0.5},\n    [SegmentEndFirst][2] = {0.5, 0.0},\n    [SegmentEndFirst][3] = {0.0, 0.0},\n    \n    [SegmentEndSecond][0] = {0.5, 0.0},\n    [SegmentEndSecond][1] = {0.5, 0.5},\n    [SegmentEndSecond][2] = {0.0, 0.0},\n    [SegmentEndSecond][3] = {0.0, 0.5},\n};\n\n@implementation RVPointMeshController\n\n\n- (void)setupVAO\n{\n    glGenVertexArraysOES(1, &_VAO);\n    glBindVertexArrayOES(_VAO);\n    \n    \n    glGenBuffers(1, &_vertexBuffer);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    glBufferData(GL_ARRAY_BUFFER, VertexLimit * sizeof(PointVertex), NULL, GL_DYNAMIC_DRAW);\n    \n    glGenBuffers(1, &_indexBuffer);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, IndexLimit * sizeof(GLushort), NULL, GL_DYNAMIC_DRAW);\n    \n    glEnableVertexAttribArray(VertexAttribPosition);\n    glVertexAttribPointer(VertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(PointVertex), (void *)offsetof(PointVertex, p));\n    \n    glEnableVertexAttribArray(VertexAttribTexCoord);\n    glVertexAttribPointer(VertexAttribTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(PointVertex), (void *)offsetof(PointVertex, uv));\n    \n    glEnableVertexAttribArray(VertexAttribAlpha);\n    glVertexAttribPointer(VertexAttribAlpha,    1, GL_FLOAT, GL_FALSE, sizeof(PointVertex), (void *)offsetof(PointVertex, alpha));\n    \n    glBindVertexArrayOES(0);\n}\n\n\n- (void)updateBuffersWithPointSprites:(NSArray *)pointSprites\n{\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);\n    PointVertex *vertexData = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);\n    GLushort *indexData = glMapBufferOES(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_OES);\n    \n    PointVertex v[4];\n    GLushort i[6];\n\n    GLuint totalIndicies = 0;\n    GLuint totalVertices = 0;\n    \n    for (RVPointSprite *pointSprite in pointSprites) {\n        \n        if (totalVertices + 4 > VertexLimit) {\n            break;\n        }\n        \n        GLKVector2 offset = PointTexTypeOffset[pointSprite.type];\n        NSInteger end = pointSprite.segmentEnd;\n        float alpha = pointSprite.alpha;\n        float size = pointSprite.scale * _pointSize/2.0;\n        GLKVector2 center = pointSprite.position;\n        GLKVector3 translation = pointSprite.extraTranslationVector;\n        center.x += translation.x;\n        center.y += translation.y;\n        \n        v[0].uv = GLKVector2Add(offset, PointTexEndPos[end][0]);\n        v[1].uv = GLKVector2Add(offset, PointTexEndPos[end][1]);\n        v[2].uv = GLKVector2Add(offset, PointTexEndPos[end][2]);\n        v[3].uv = GLKVector2Add(offset, PointTexEndPos[end][3]);\n        \n        v[0].p = GLKVector2Make(center.x + size, center.y + size);\n        v[1].p = GLKVector2Make(center.x - size, center.y + size);\n        v[2].p = GLKVector2Make(center.x + size, center.y - size);\n        v[3].p = GLKVector2Make(center.x - size, center.y - size);\n        \n        v[0].alpha = alpha;\n        v[1].alpha = alpha;\n        v[2].alpha = alpha;\n        v[3].alpha = alpha;\n        \n        memcpy(vertexData, v, sizeof(v));\n        vertexData += sizeof(v)/sizeof(v[0]);\n        \n        i[0] = totalVertices + 0;\n        i[1] = totalVertices + 2;\n        i[2] = totalVertices + 1;\n        \n        i[3] = totalVertices + 1;\n        i[4] = totalVertices + 2;\n        i[5] = totalVertices + 3;\n        \n        memcpy(indexData, i, sizeof(i));\n        indexData += sizeof(i)/sizeof(i[0]);\n        \n        totalIndicies += 6;\n        totalVertices += 4;\n    }\n    \n    _indiciesCount = totalIndicies;\n    \n    glUnmapBufferOES(GL_ELEMENT_ARRAY_BUFFER);\n    glUnmapBufferOES(GL_ARRAY_BUFFER);\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVPointShader.fsh",
    "content": "\nvarying lowp vec2 texCoordVarying;\nvarying lowp float alphaVarying;\n\nuniform lowp sampler2D texSampler;\n\nvoid main()\n{\n    lowp vec4 color = texture2D(texSampler, texCoordVarying);\n    color.a *= alphaVarying;\n    \n    gl_FragColor = color;\n}\n\n"
  },
  {
    "path": "Revolved/RVPointShader.h",
    "content": "//\n//  RVPointShader.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"BCShader.h\"\n\n@interface RVPointShader : BCShader\n\n@property (nonatomic) GLint viewProjectionMatrixUniform;\n@property (nonatomic) GLint texSamplerUniform;\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVPointShader.m",
    "content": "//\n//  RVPointShader.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 15.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPointShader.h\"\n\n@implementation RVPointShader\n\n- (void)bindAttributeLocations\n{\n    glBindAttribLocation(self.program, VertexAttribPosition, \"position\");\n    glBindAttribLocation(self.program, VertexAttribTexCoord, \"texCoord\");\n    glBindAttribLocation(self.program, VertexAttribAlpha, \"alpha\");\n}\n\n- (void)getUniformLocations\n{\n    self.viewProjectionMatrixUniform = glGetUniformLocation(self.program, \"viewProjectionMatrix\");\n    self.texSamplerUniform = glGetUniformLocation(self.program, \"texSampler\");\n\n}\n\n- (NSString *)shaderName\n{\n    return @\"RVPointShader\";\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVPointShader.vsh",
    "content": "\nattribute vec4 position;\nattribute vec2 texCoord;\nattribute float alpha;\n\nvarying vec2 texCoordVarying;\nvarying float alphaVarying;\n\nuniform mat4 viewProjectionMatrix;\n\nvoid main()\n{\n    texCoordVarying = texCoord;\n    alphaVarying = alpha;\n    \n    gl_Position = viewProjectionMatrix * position;\n}\n\n"
  },
  {
    "path": "Revolved/RVPointSprite.h",
    "content": "//\n//  RVPointSprite.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 19.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSprite.h\"\n#import \"RVPoint.h\"\n\n@interface RVPointSprite : RVSprite\n\n@property (nonatomic) PointType type;\n@property (nonatomic) SegmentEnd segmentEnd;\n@property (nonatomic) GLKVector2 position;\n@property (nonatomic) GLKVector3 extraTranslationVector;\n\n@property (nonatomic) float alpha;\n@property (nonatomic) float scale;\n\n@end\n"
  },
  {
    "path": "Revolved/RVPointSprite.m",
    "content": "//\n//  RVPointSprite.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 19.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPointSprite.h\"\n\n@implementation RVPointSprite\n\n@end\n"
  },
  {
    "path": "Revolved/RVPreviewViewController.h",
    "content": "//\n//  PreviewViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import <GLKit/GLKit.h>\n\n@class RVModelSprite, RVPreviewViewController, CameraController, RVAxisSprite;\n\n\n@protocol RVPreviewViewControllerDelegate <NSObject>\n\n- (void)previewControllerDidTapCameraButton:(RVPreviewViewController *)controller;\n- (void)previewControllerDidTapBackButton:(RVPreviewViewController *)controller;\n\n@end\n\n@interface RVPreviewViewController : UIViewController\n\n@property (nonatomic, weak) id<RVPreviewViewControllerDelegate> delegate;\n@property (nonatomic, strong) RVModelSprite *modelSprite;\n\n@property (nonatomic, strong) CameraController *cameraController;\n\n- (void)tick;\n- (void)assignSegmentsToSprite:(NSOrderedSet *)segments;\n\n- (void)animateInWithDuration:(NSTimeInterval)duration;\n- (void)animateOutWithDuration:(NSTimeInterval)duration;\n\n- (void)flashSegmentLimitAlert;\n\n@end\n"
  },
  {
    "path": "Revolved/RVPreviewViewController.m",
    "content": "//\n//  PreviewViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVPreviewViewController.h\"\n#import \"CameraController.h\"\n#import \"Color.h\"\n\n#import \"RVModelSprite.h\"\n#import \"RVAxisSprite.h\"\n#import \"RVFloatAnimation.h\"\n\n\n@interface RVPreviewViewController() <UIGestureRecognizerDelegate>\n\n@property (weak, nonatomic) IBOutlet UIButton *backButton;\n@property (weak, nonatomic) IBOutlet UIButton *cameraButton;\n@property (weak, nonatomic) IBOutlet UIImageView *segmentLimitImage;\n\n@end\n\n@implementation RVPreviewViewController\n\n- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil\n{\n    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];\n    if (self) {\n        _modelSprite = [RVModelSprite new];\n    }\n    return self;\n}\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    [self.view addGestureRecognizer:self.cameraController.panRecognizer];\n    [self.view addGestureRecognizer:self.cameraController.rotationRecognizer];\n    \n    self.cameraButton.exclusiveTouch = YES;\n    self.backButton.exclusiveTouch = YES;\n    self.segmentLimitImage.hidden = YES;\n}\n\n- (void)viewDidLayoutSubviews\n{\n    [self.cameraController setRenderSurfaceSize:self.view.bounds.size];\n}\n\n- (void)tick\n{\n    self.modelSprite.quaternion = self.cameraController.quaternion;\n}\n\n- (void)resetRecognizers\n{\n    self.cameraController.panRecognizer.enabled = NO;\n    self.cameraController.panRecognizer.enabled = YES;\n    \n    self.cameraController.rotationRecognizer.enabled = NO;\n    self.cameraController.rotationRecognizer.enabled = YES;\n}\n\n- (void)flashSegmentLimitAlert\n{\n    self.segmentLimitImage.alpha = 0.0f;\n    self.segmentLimitImage.hidden = NO;\n    \n    [UIView animateWithDuration:0.1 animations:^{\n        self.segmentLimitImage.alpha = 1.0f;\n    } completion:^(BOOL finished) {\n        if (finished) {\n            [UIView animateWithDuration:2.0 animations:^{\n                self.segmentLimitImage.alpha = 0.0f;\n            } completion:^(BOOL finished) {\n                if (finished) {\n                    self.segmentLimitImage.hidden = YES;\n                }\n            }];\n        }\n    }];\n}\n\n- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event\n{\n    [super touchesBegan:touches withEvent:event];\n    [self.cameraController stop];\n    \n    RVFloatAnimation *alphaAnimation = [RVFloatAnimation floatAnimationFromValue:self.modelSprite.axisAlpha toValue:1.0 withDuration:0.3];\n    alphaAnimation.delay = self.modelSprite.axisAlpha == 0.0f ? 0.1 : 0.0f;\n    [self.modelSprite addAnimation:alphaAnimation forKey:@\"axisAlpha\"];\n}\n\n- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event\n{\n    RVFloatAnimation *alphaAnimation = [RVFloatAnimation floatAnimationFromValue:self.modelSprite.axisAlpha toValue:0.0 withDuration:0.3];\n    alphaAnimation.delay = self.modelSprite.axisAlpha == 1.0f ? 0.5 : 0.0f;\n    [self.modelSprite addAnimation:alphaAnimation forKey:@\"axisAlpha\"];\n}\n\n- (IBAction)cameraButtonTapped:(UIButton *)sender\n{\n    [self resetRecognizers];\n    [self.delegate previewControllerDidTapCameraButton:self];\n}\n\n- (IBAction)backButtonTapped:(UIButton *)sender\n{\n    [self resetRecognizers];\n    [self.delegate previewControllerDidTapBackButton:self];\n}\n\n- (void)assignSegmentsToSprite:(NSOrderedSet *)segments\n{\n    self.cameraButton.enabled = segments.count > 0;\n    self.modelSprite.drawnSegments = segments.array;\n}\n\n- (void)animateInWithDuration:(NSTimeInterval)duration\n{\n    self.backButton.alpha = 0.0f;\n    self.cameraButton.alpha = 0.0f;\n    [self.cameraController resetPosition];\n    self.modelSprite.quaternion = self.cameraController.quaternion;\n\n    [UIView animateWithDuration:duration animations:^{\n        self.backButton.alpha = 1.0f;\n        self.cameraButton.alpha = 1.0f;\n    }];\n}\n\n- (void)animateOutWithDuration:(NSTimeInterval)duration\n{\n    [self.cameraController animateToStartPositionWithDuration:duration*0.9];\n    \n    RVFloatAnimation *alphaAnimation = [RVFloatAnimation floatAnimationFromValue:self.modelSprite.axisAlpha toValue:0.0 withDuration:duration];\n    [self.modelSprite addAnimation:alphaAnimation forKey:@\"axisAlpha\"];\n    \n    [UIView animateWithDuration:duration animations:^{\n        self.backButton.alpha = 0.0f;\n        self.cameraButton.alpha = 0.0f;\n    }];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVPreviewViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVPreviewViewController\">\n            <connections>\n                <outlet property=\"backButton\" destination=\"1cE-rw-4Ha\" id=\"3Jm-XP-hMR\"/>\n                <outlet property=\"cameraButton\" destination=\"Add-c6-LJh\" id=\"Air-Th-DwI\"/>\n                <outlet property=\"segmentLimitImage\" destination=\"QLd-Pt-sRi\" id=\"d2Y-iK-IBo\"/>\n                <outlet property=\"view\" destination=\"1\" id=\"22Z-k0-cSR\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"576\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"1cE-rw-4Ha\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"60\" height=\"62\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <inset key=\"imageEdgeInsets\" minX=\"0.0\" minY=\"0.0\" maxX=\"11\" maxY=\"3\"/>\n                    <state key=\"normal\" image=\"BackButton\"/>\n                    <connections>\n                        <action selector=\"backButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"jWr-Zm-Cfo\"/>\n                    </connections>\n                </button>\n                <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"Add-c6-LJh\">\n                    <rect key=\"frame\" x=\"258\" y=\"705\" width=\"60\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <state key=\"normal\" image=\"Camera\"/>\n                    <connections>\n                        <action selector=\"cameraButtonTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"1jS-Vq-nIo\"/>\n                    </connections>\n                </button>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"SegmentLimit\" id=\"QLd-Pt-sRi\">\n                    <rect key=\"frame\" x=\"214\" y=\"19\" width=\"149\" height=\"24\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n            <simulatedStatusBarMetrics key=\"simulatedStatusBarMetrics\" statusBarStyle=\"blackOpaque\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"BackButton\" width=\"12\" height=\"22\"/>\n        <image name=\"Camera\" width=\"36\" height=\"28\"/>\n        <image name=\"SegmentLimit\" width=\"149\" height=\"24\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVQuaternionAnimation.h",
    "content": "//\n//  RVQuaternionAnimation.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 08.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAnimation.h\"\n\nextern GLKQuaternion BaseQuaternion;\n\n@interface RVQuaternionAnimation : RVAnimation\n\n@property (nonatomic) GLKQuaternion from;\n@property (nonatomic) GLKQuaternion to;\n\n- (GLKQuaternion)valueForProgress:(float)progress;\n+ (RVQuaternionAnimation *)quaternionAnimationFromValue:(GLKQuaternion)fromValue toValue:(GLKQuaternion)toValue withDuration:(NSTimeInterval)duration;\n\n@end\n"
  },
  {
    "path": "Revolved/RVQuaternionAnimation.m",
    "content": "//\n//  RVQuaternionAnimation.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 08.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVQuaternionAnimation.h\"\n\nGLKQuaternion BaseQuaternion;\n\n@implementation RVQuaternionAnimation\n\n__attribute__((constructor))\nstatic void initializeBaseQuaternion() {\n    BaseQuaternion = GLKQuaternionMakeWithAngleAndAxis(0.615479709, 1, 0, 0);\n}\n\n- (GLKQuaternion)valueForProgress:(float)progress\n{\n    return GLKQuaternionSlerp(_from, _to, progress);\n}\n\n\n+ (RVQuaternionAnimation *)quaternionAnimationFromValue:(GLKQuaternion)fromValue toValue:(GLKQuaternion)toValue withDuration:(NSTimeInterval)duration\n{\n    RVQuaternionAnimation *animation = [RVQuaternionAnimation new];\n    animation.from = fromValue;\n    animation.to = toValue;\n    animation.duration = duration;\n    \n    return animation;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVRenderingController.h",
    "content": "//\n//  RVRenderingController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 08.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"RVModelMeshController.h\"\n#import \"RVAxisMeshController.h\"\n#import \"RVGuidlineDotMeshController.h\"\n#import \"RVLineMeshController.h\"\n#import \"RVPointMeshController.h\"\n\n#import \"CameraController.h\"\n#import \"Renderer.h\"\n\n@interface RVRenderingController : NSObject\n\n@property (nonatomic, strong) Renderer *renderer;\n@property (nonatomic, strong) CameraController *cameraController;\n\n@property (nonatomic, strong) RVModelMeshController *modelController;\n@property (nonatomic, strong) RVAxisMeshController *axisController;\n@property (nonatomic, strong) RVGuidlineDotMeshController *guidelineController;\n@property (nonatomic, strong) RVLineMeshController *lineController;\n@property (nonatomic, strong) RVPointMeshController *pointController;\n\n- (void)setupOpenGL;\n\n@end\n"
  },
  {
    "path": "Revolved/RVRenderingController.m",
    "content": "//\n//  RVRenderingController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 08.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVRenderingController.h\"\n#import \"Camera.h\"\n\n@implementation RVRenderingController\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _modelController = [[RVModelMeshController alloc] init];\n        _axisController = [[RVAxisMeshController alloc] init];\n        _guidelineController = [[RVGuidlineDotMeshController alloc] init];\n        _lineController = [[RVLineMeshController alloc] init];\n        _pointController = [[RVPointMeshController alloc] init];\n        _cameraController = [[CameraController alloc] init];\n        \n        _renderer = [[Renderer alloc] init];\n        _renderer.camera = [[Camera alloc] init];\n        _renderer.modelController = _modelController;\n        _renderer.axisController = _axisController;\n        _renderer.guidlineController = _guidelineController;\n        _renderer.lineController = _lineController;\n        _renderer.pointController = _pointController;\n    }\n    return self;\n}\n\n- (void)setupOpenGL\n{\n    [self.renderer setupOpenGL];\n    \n    [self.modelController setupOpenGL];\n    [self.axisController setupOpenGL];\n    [self.guidelineController setupOpenGL];\n    [self.lineController setupOpenGL];\n    [self.pointController setupOpenGL];\n}\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVRevolvedTutorialPage.h",
    "content": "//\n//  RVRevolvedTutorialPage.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialPage.h\"\n\n@interface RVRevolvedTutorialPage : RVTutorialPage\n\n@end\n"
  },
  {
    "path": "Revolved/RVRevolvedTutorialPage.m",
    "content": "//\n//  RVRevolvedTutorialPage.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVRevolvedTutorialPage.h\"\n#import \"RVTutorialLineImageView.h\"\n\n@interface RVRevolvedTutorialPage()\n\n@property (weak, nonatomic) IBOutlet RVTutorialLineImageView *line;\n@property (weak, nonatomic) IBOutlet UIImageView *backImageView;\n@property (weak, nonatomic) IBOutlet UIImageView *frontImageView;\n\n@end\n\n@implementation RVRevolvedTutorialPage\n\n\n- (void)setDisplayPercent:(float)displayPercent\n{\n    [super setDisplayPercent:displayPercent];\n    \n    const CGSize TopSize = {58, 32};\n    const CGSize BottomSize = {156, 92};\n    \n    const CGFloat Top = 190.0f;\n    const CGFloat Bottom = 323.0f;\n    \n    float progress = [self progressForPercent:displayPercent];\n    float angle = 2.0 * M_PI * progress + M_PI_2;\n    \n    float s = sinf(angle);\n    float c = cosf(angle);\n    \n    float alpha = MIN(MAX(0.0f, progress), 1.0f);\n\n    CGFloat x = self.bounds.size.width/2.0f;\n    \n    CGPoint start = CGPointMake(x + c * TopSize.width, Top + s * TopSize.height);\n    CGPoint end = CGPointMake(x + c * BottomSize.width, Bottom + s * BottomSize.height);\n    \n    if (self.backImageView) {\n        self.backImageView.alpha = alpha;\n        self.frontImageView.alpha = alpha;\n        self.line.alpha = 1.0 - alpha;\n    }\n\n    [self.line positionFromPoint:start toPoint:end];\n}\n\n- (NSString *)descriptionString\n{\n    return self.backImageView ?  @\"...to create your model\" : @\"Segments get Revolved around the axis...\";\n}\n\n- (float)progressForPercent:(float)percent\n{\n    return percent - 0.2;\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVRevolvedTutorialPage.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVRevolvedTutorialPage\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"576\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialAxis3D\" id=\"xjy-lE-GHh\">\n                    <rect key=\"frame\" x=\"350\" y=\"111\" width=\"1\" height=\"353\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" id=\"yRK-E9-6C7\" customClass=\"RVTutorialLineImageView\">\n                    <rect key=\"frame\" x=\"379\" y=\"182\" width=\"240\" height=\"128\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <outlet property=\"line\" destination=\"yRK-E9-6C7\" id=\"MXp-c3-He4\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TutorialAxis3D\" width=\"2\" height=\"706\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVRevolvedTutorialPageSolid.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVRevolvedTutorialPage\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"576\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" id=\"yRK-E9-6C7\" customClass=\"RVTutorialLineImageView\">\n                    <rect key=\"frame\" x=\"70\" y=\"321\" width=\"57\" height=\"51\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialRevolvedBack\" id=\"0OT-Tq-kKO\">\n                    <rect key=\"frame\" x=\"212\" y=\"158\" width=\"276\" height=\"123\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialRevolvedFront\" id=\"lwd-C4-Smv\">\n                    <rect key=\"frame\" x=\"194\" y=\"180\" width=\"312\" height=\"238\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <outlet property=\"backImageView\" destination=\"0OT-Tq-kKO\" id=\"0Xb-hg-egE\"/>\n                <outlet property=\"frontImageView\" destination=\"lwd-C4-Smv\" id=\"Nii-uA-ogc\"/>\n                <outlet property=\"line\" destination=\"yRK-E9-6C7\" id=\"MXp-c3-He4\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TutorialRevolvedBack\" width=\"552\" height=\"246\"/>\n        <image name=\"TutorialRevolvedFront\" width=\"624\" height=\"476\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVRootViewController.h",
    "content": "//\n//  RVRootViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 24.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVRootViewController : UIViewController\n\n- (void)handleOpeningURL:(NSURL *)url;\n\n@end\n"
  },
  {
    "path": "Revolved/RVRootViewController.m",
    "content": "//\n//  RVRootViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 24.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <MessageUI/MessageUI.h>\n#import \"MFMailComposeViewController+SendIfPossible.h\"\n\n#import \"RVRootViewController.h\"\n#import \"RVModelManager.h\"\n#import \"RVRenderingController.h\"\n\n#import \"RVModelViewController.h\"\n#import \"RVModelsViewController.h\"\n#import \"RVExportViewController.h\"\n#import \"RVTutorialViewController.h\"\n\n#import \"RVModelSprite.h\"\n#import \"RVOpenGLView.h\"\n#import \"RVAnimator.h\"\n#import \"RVUserDefaults.h\"\n#import \"RVColorProvider.h\"\n\n#import \"Camera.h\"\n\n\n#import \"NSError+RevolvedErrors.h\"\n\n\nstatic const CGFloat PreviewWidth = 576.0f;\nstatic const CGFloat PreviewHeight = 768.0f;\n\n@interface RVRootViewController () <RVModelsViewControllerDelegate, RVModelsViewControllerDataSource, RVModelViewControllerDelegate, MFMailComposeViewControllerDelegate>\n\n@property (nonatomic, strong) IBOutlet RVOpenGLView *openGLView;\n@property (nonatomic, strong) EAGLContext *context;\n@property (nonatomic, strong) RVRenderingController *renderingController;\n@property (nonatomic, strong) CADisplayLink *displayLink;\n@property (nonatomic) CFTimeInterval previousTimeStamp;\n\n@property (nonatomic, strong) RVModelManager *modelManager;\n@property (nonatomic, strong) RVModel *currentModel;\n\n@property (nonatomic) BOOL showsModel;\n@property (nonatomic, strong) RVModelViewController *modelViewController;\n@property (nonatomic, strong) RVModelsViewController *modelsViewController;\n@property (nonatomic, strong) RVExportViewController *exportViewController;\n@property (nonatomic, strong) RVTutorialViewController *tutorialViewController;\n\n@property (nonatomic) BOOL pendingImportAnimation;\n\n\n\n@end\n\n\n@implementation RVRootViewController\n\n- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil\n{\n    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];\n    if (self) {\n        \n        _modelManager = [[RVModelManager alloc] init];\n        _renderingController = [[RVRenderingController alloc] init];\n        _renderingController.renderer.camera = [[Camera alloc] init];\n        _renderingController.renderer.camera.aspect = PreviewWidth/PreviewHeight;\n        _renderingController.renderer.camera.distance = 14.6f;\n        \n        _modelViewController = [[RVModelViewController alloc] init];\n        _modelViewController.previewWidth = PreviewWidth;\n        _modelViewController.delegate = self;\n        _modelViewController.renderingController = _renderingController;\n        \n        _modelsViewController = [[RVModelsViewController alloc] init];\n        _modelsViewController.delegate = self;\n        _modelsViewController.dataSource = self;\n        _modelsViewController.previewSize = CGSizeMake(PreviewWidth, PreviewHeight);\n        _modelsViewController.renderingController = _renderingController;\n\n        _exportViewController = [[RVExportViewController alloc] init];\n        \n        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stopDrawing) name:UIApplicationWillResignActiveNotification object:nil];\n        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startDrawing) name:UIApplicationDidBecomeActiveNotification object:nil];\n        \n        [self importStartModelsIfNeeded];\n    }\n    return self;\n}\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    \n    self.view.backgroundColor = [UIColor rv_backgroundColor];\n    \n    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];\n    [EAGLContext setCurrentContext: self.context];\n    self.openGLView.context = self.context;\n    self.openGLView.opaque = YES;\n    [self.renderingController setupOpenGL];\n    \n    [self addChildViewController:self.modelViewController];\n    [self.view addSubview:self.modelViewController.view];\n    [self.modelViewController didMoveToParentViewController:self];\n\n    self.modelViewController.view.hidden = YES;\n    \n    [self addChildViewController:self.modelsViewController];\n    [self.view addSubview:self.modelsViewController.view];\n    [self.modelsViewController didMoveToParentViewController:self];\n\n    self.modelsViewController.delegate = self;\n    [self.modelsViewController reloadData];\n\n    [self addChildViewController:self.exportViewController];\n    [self.view addSubview:self.exportViewController.view];\n    [self.exportViewController didMoveToParentViewController:self];\n    \n    \n    self.showsModel = NO;\n    \n    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick:)];\n    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];\n}\n\n- (void)viewWillAppear:(BOOL)animated\n{\n    [super viewWillAppear:animated];\n    [self displayLinkTick:self.displayLink];\n}\n\n- (BOOL)prefersStatusBarHidden\n{\n    return YES;\n}\n\n- (void)importStartModelsIfNeeded\n{\n    if (![[NSUserDefaults standardUserDefaults] boolForKey:HasImportedStartModelsKey]) {\n        NSError *error;\n        for (int i = 1; i <=3; i++) {\n            NSString *fileName = [NSString stringWithFormat:@\"model%d\", i];\n            NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:@\"rvlvd\"];\n            NSData *data = [NSData dataWithContentsOfFile:path];\n            [_modelManager importModelData:data error:&error];\n        }\n\n        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:HasImportedStartModelsKey];\n        [[NSUserDefaults standardUserDefaults] synchronize];\n    }\n}\n\n#pragma mark - Rendering\n\n\n- (void)update:(NSTimeInterval)dt\n{\n    [self.renderingController.cameraController displayTick];\n    [self.renderingController.renderer.camera updateMatrices];\n    \n    if (self.showsModel) {\n        [self.modelViewController tick];\n    } else {\n        [self.modelsViewController tick];\n    }\n\n    \n    [[RVAnimator sharedAnimator] tick:dt];\n}\n\n\n\n\n- (void)displayLinkTick:(CADisplayLink *)sender\n{\n    CFTimeInterval timeStamp = [sender timestamp];\n    CFTimeInterval dt = timeStamp - self.previousTimeStamp;\n    \n    if (self.previousTimeStamp == 0.0) {\n        dt = 1.0/60.0;\n    }\n    \n    self.previousTimeStamp = timeStamp;\n    \n    [self update:dt];\n\n    [self.openGLView presentWithRenderingBlock:^{\n        [self.renderingController.renderer render];\n    }];\n}\n\n- (void)stopDrawing\n{\n    self.displayLink.paused = YES;\n}\n\n- (void)startDrawing\n{\n    self.displayLink.paused = NO;\n}\n\n- (void)setShowsModel:(BOOL)showsModel\n{\n    _showsModel = showsModel;\n    \n    self.modelViewController.view.hidden = !showsModel;\n    self.modelsViewController.view.hidden = showsModel;\n    \n    CGFloat scale = [[UIScreen mainScreen] scale];\n    \n    if (showsModel) {\n        self.renderingController.renderer.meshViewport = CGRectApplyAffineTransform(self.modelViewController.previewFrame, CGAffineTransformMakeScale(scale, scale));\n        self.renderingController.renderer.drawingViewport = CGRectApplyAffineTransform(self.modelViewController.drawFrame, CGAffineTransformMakeScale(scale, scale));\n        self.renderingController.renderer.drawingTransformMatrix = self.modelViewController.drawMatrix;\n    } else {\n        self.renderingController.renderer.meshViewport = CGRectApplyAffineTransform(self.view.bounds, CGAffineTransformMakeScale(scale, scale));\n        self.renderingController.renderer.drawingViewport = CGRectZero;\n    }\n}\n\n#pragma mark - RVModelViewControllerDelegate\n\n- (NSString *)documentsPaths\n{\n    NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);\n    NSString *documentsDirectory = [paths objectAtIndex:0];\n    return documentsDirectory;\n}\n\n- (void)modelViewControllerDidRequestBack:(RVModelViewController *)controller\n{\n    [self.modelViewController animateOut];\n}\n\n- (void)modelViewControllerDidAnimateOut:(RVModelViewController *)controller\n{\n    self.showsModel = NO;\n    if (self.pendingImportAnimation) {\n        self.pendingImportAnimation = NO;\n        \n        [self.modelsViewController importModelSpriteForModelAtIndex:0];\n    }\n    \n    [self.modelsViewController zoomOut];\n}\n\n- (void)modelViewControllerDidAnimateIn:(RVModelViewController *)controller\n{\n    if (![[NSUserDefaults standardUserDefaults] boolForKey:HasPlayedTutorialKey]) {\n        [self showTutorial];\n        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:HasPlayedTutorialKey];\n        [[NSUserDefaults standardUserDefaults] synchronize];\n    }\n}\n\n- (void)modelViewController:(RVModelViewController *)controller didChangeModel:(RVModel *)model\n{\n    //NSDate *startMeasureDate_BC = [NSDate date];\n    \n    [self.modelManager saveModel:model];\n    \n   // NSLog(@\"Measured time: %lg\", [[NSDate date] timeIntervalSinceDate:startMeasureDate_BC]);\n}\n\n- (void)modelViewControllerDidRequestSharePicture:(RVModelViewController *)controller\n{\n    [self sharePicture];\n}\n\n\n- (void)showTutorial\n{\n    self.tutorialViewController = [[RVTutorialViewController alloc] init];\n    \n    __weak RVTutorialViewController *weakController = self.tutorialViewController;\n    \n    [self addChildViewController:self.tutorialViewController];\n    [self.view addSubview:self.tutorialViewController.view];\n    [self.tutorialViewController didMoveToParentViewController:self];\n    \n    [self.tutorialViewController presentWithPostDismissalBlock:^{\n        [weakController willMoveToParentViewController:nil];\n        [weakController.view removeFromSuperview];\n        [weakController removeFromParentViewController];\n        \n        self.tutorialViewController = nil;\n    }];\n}\n\n#pragma mark - RVModelsViewControllerDelegate & Data Source\n\n- (NSUInteger)modelsViewControllerNumberOfModels:(RVModelsViewController *)controller\n{\n    return self.modelManager.numberOfModels;\n}\n\n- (RVModel *)modelsViewController:(RVModelsViewController *)controller modelAtIndex:(NSUInteger)modelIndex\n{\n    return [self.modelManager modelAtIndex:modelIndex];\n}\n\n- (CGRect)modelsViewControllerDestinationRectForSelectedModel:(RVModelsViewController *)controller\n{\n    return CGRectMake(0, 0, PreviewWidth, PreviewHeight);\n}\n\n\n\n- (void)modelsViewControllerDidAddModel:(RVModelsViewController *)controller\n{\n    RVModel *newModel = [self.modelManager createNewModel];\n    [self.modelViewController setupModel:newModel];\n    [controller addNewModelSpriteForModelAtIndex:0];\n}\n\n- (void)modelsViewController:(RVModelsViewController *)controller didSelectModelAtIndex:(NSUInteger)modelIndex\n{\n    [self.modelViewController setupModel:[self.modelManager modelAtIndex:modelIndex]];\n}\n\n- (void)modelsViewController:(RVModelsViewController *)controller didDeleteModelAtIndex:(NSUInteger)modelIndex\n{\n    [self.modelManager deleteModelAtIndex:modelIndex];\n}\n\n- (void)modelsViewController:(RVModelsViewController *)controller didCloneModelAtIndex:(NSUInteger)modelIndex\n{\n    [self.modelManager cloneModelAtIndex:modelIndex];\n}\n\n- (void)modelsViewController:(RVModelsViewController *)controller didShareModelAtIndex:(NSUInteger)modelIndex\n{\n    [self exportModelAtIndex:modelIndex];\n}\n\n- (void)modelsViewController:(RVModelsViewController *)controller didMoveModelAtIndex:(NSUInteger)sourceIndex toIndex:(NSUInteger)targetIndex\n{\n    [self.modelManager moveModelAtIndex:sourceIndex toIndex:targetIndex];\n}\n\n\n- (void)modelsViewController:(RVModelsViewController *)controller didZoomInToModelAtIndex:(NSUInteger)modelIndex\n{\n    self.showsModel = YES;\n    [self.modelViewController animateIn];\n}\n\n- (void)modelsViewControllerDidZoomOut:(RVModelsViewController *)controller\n{\n\n}\n\n- (void)modelsViewControllerDidRequestTutorial:(RVModelsViewController *)controller\n{\n    [self showTutorial];\n    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:HasPlayedTutorialKey];\n}\n\n\n- (void)showImportedModel\n{\n    if (self.showsModel) {\n        self.pendingImportAnimation = YES;\n        [self.modelViewController animateOut];\n    } else {\n        [self.modelsViewController importModelSpriteForModelAtIndex:0];\n    }\n}\n\n\n#pragma mark - Export\n\n- (void)exportModelAtIndex:(NSInteger)modelIndex\n{\n    RVModel *model = [self.modelManager modelAtIndex:modelIndex];\n    \n    self.exportViewController.model = model;\n    [self.exportViewController present];\n}\n\n\n- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error\n{\n    if (result == MFMailComposeResultFailed) {\n        [MFMailComposeViewController rv_showDefaultFailAlertWithError:error];\n    } else {\n        [self dismissViewControllerAnimated:YES completion:NULL];\n    }\n}\n\n\n- (void)sharePicture\n{\n    UIImage *modelImage = [self modelImage];\n\n    [self.modelViewController presentShareOptionsWithImage:modelImage];\n}\n\n\n- (UIImage *)modelImage\n{\n    UIImage *snapshotImage = [self.openGLView snapshotWithRenderingBlock:^{\n        [self.renderingController.renderer renderModelMesh];\n    }];\n    \n\n    \n    CGImageRef croppedImageRef = CGImageCreateWithImageInRect(snapshotImage.CGImage, self.renderingController.renderer.meshViewport);\n    UIImage *croppedImage = [UIImage imageWithCGImage:croppedImageRef scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationUp];\n    CGImageRelease(croppedImageRef);\n    \n    return croppedImage;\n}\n\n#pragma mark - File Importing\n\n- (void)handleOpeningURL:(NSURL *)url\n{\n    NSData *data = [NSData dataWithContentsOfURL:url];\n    \n    if (!data) {\n        [self showAlertWithError:[NSError malformedFileError]];\n        return;\n    }\n    \n    NSError *error;\n    if ([self.modelManager importModelData:data error:&error]) {\n        [self showImportedModel];\n    } else {\n        [self showAlertWithError:error];\n    }\n}\n\n- (void)showAlertWithError:(NSError *)error\n{\n    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@\"\" message:[error localizedDescription] delegate:nil cancelButtonTitle:@\"OK\" otherButtonTitles:nil];\n    [alert show];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVRootViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVRootViewController\">\n            <connections>\n                <outlet property=\"openGLView\" destination=\"ucn-c1-ZVa\" id=\"FML-U0-oXq\"/>\n                <outlet property=\"view\" destination=\"1\" id=\"ebj-lm-0kz\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view clipsSubviews=\"YES\" contentMode=\"scaleToFill\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"ucn-c1-ZVa\" customClass=\"RVOpenGLView\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                </view>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <simulatedStatusBarMetrics key=\"simulatedStatusBarMetrics\" statusBarStyle=\"blackOpaque\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n        </view>\n    </objects>\n</document>"
  },
  {
    "path": "Revolved/RVSTLExporter.h",
    "content": "//\n//  RVSTLExporter.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.11.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVExporter.h\"\n\n@interface RVSTLExporter : RVExporter\n\n@end\n"
  },
  {
    "path": "Revolved/RVSTLExporter.m",
    "content": "//\n//  RVSTLExporter.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.11.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSTLExporter.h\"\n#import \"RVModel.h\"\n#import \"RVSegment.h\"\n\n#import \"Vertex.h\"\n#import \"Constants.h\"\n\n@implementation RVSTLExporter\n\ntypedef struct FaceStruct {\n    GLKVector3 normal;\n    GLKVector3 v1;\n    GLKVector3 v2;\n    GLKVector3 v3;\n    u_int16_t attrib;\n} FaceStruct;\n\nstatic const size_t FaceStructSize = 50;\n\n\nstatic inline void printVertexCoords(GLKVector3 v, NSFileHandle *handle)\n{\n    [handle writeData:[NSData dataWithBytesNoCopy:&v length:sizeof(v) freeWhenDone:NO]];\n}\n\nstatic inline void fillFace(FaceStruct *face, GLKVector3 v1, GLKVector3 v2, GLKVector3 v3)\n{\n    face->normal = GLKVector3CrossProduct(GLKVector3Subtract(v1, v2), GLKVector3Subtract(v3, v2));\n    face->v1 = v1;\n    face->v2 = v2;\n    face->v3 = v3;\n}\n\n\n- (void)appendModel:(RVModel *)model toHandle:(NSFileHandle *)handle\n{\n    u_int32_t totalTesselationSegments = 0;\n    \n    for (RVSegment *segment in model.segments) {\n        totalTesselationSegments += [segment modelTesselationSegments];\n    }\n    \n    u_int32_t totalTriangles = totalTesselationSegments * Spans * StripesPerSpan * 2;\n    u_int8_t header[80] = \"Model from Revolved\";\n    [handle writeData:[NSData dataWithBytesNoCopy:header length:sizeof(header) freeWhenDone:NO]];\n    [handle writeData:[NSData dataWithBytesNoCopy:&totalTriangles length:sizeof(totalTriangles) freeWhenDone:NO]];\n    \n    \n    GLKMatrix4 rotationMatrix = GLKMatrix4MakeRotation(2.0 * M_PI / (Spans * StripesPerSpan), 0.0, 0.0, 1.0);\n    \n    u_int8_t bandFaces[2 * Spans * StripesPerSpan * FaceStructSize];\n    \n    FaceStruct face = {0};\n    \n    for (RVSegment *segment in model.segments) {\n        \n        NSUInteger tesselationSegments = [segment modelTesselationSegments];\n        SegmentTesselator tessalator = segment.tesselator;\n        SegmentTesselation previousTess = tessalator(0.0);\n        \n        for (int seg = 1; seg < tesselationSegments + 1; seg++) {\n            \n            SegmentTesselation tess = tessalator((double)seg/(double)tesselationSegments);\n            \n            GLKVector3 a = GLKVector3Make(0.0, previousTess.p.x, previousTess.p.y);\n            GLKVector3 b = GLKVector3Make(0.0, tess.p.x, tess.p.y);\n            GLKVector3 c = GLKMatrix4MultiplyVector3(rotationMatrix, b);\n            GLKVector3 d = GLKMatrix4MultiplyVector3(rotationMatrix, a);\n            \n            for (int stripe = 0; stripe < Spans * StripesPerSpan; stripe++) {\n                \n                face.normal = GLKVector3CrossProduct(GLKVector3Subtract(a, b), GLKVector3Subtract(d, b));\n                face.v1 = a;\n                face.v2 = b;\n                face.v3 = d;\n                \n                memcpy(&bandFaces[(2 * stripe + 0)*FaceStructSize], &face, FaceStructSize);\n               \n                face.normal = GLKVector3CrossProduct(GLKVector3Subtract(d, b), GLKVector3Subtract(c, b));\n                face.v1 = d;\n                face.v2 = b;\n                face.v3 = c;\n                \n                memcpy(&bandFaces[(2 * stripe + 1)*FaceStructSize], &face, FaceStructSize);\n                \n                b = c;\n                a = d;\n                \n                if (stripe + 1 == Spans * StripesPerSpan) {\n                    c = GLKVector3Make(0.0, tess.p.x, tess.p.y);\n                    d = GLKVector3Make(0.0, previousTess.p.x, previousTess.p.y);\n                } else {\n                    c = GLKMatrix4MultiplyVector3(rotationMatrix, c);\n                    d = GLKMatrix4MultiplyVector3(rotationMatrix, d);\n                }\n            }\n            \n            [handle writeData:[NSData dataWithBytesNoCopy:&bandFaces length:sizeof(bandFaces) freeWhenDone:NO]];\n\n            previousTess = tess;\n        }\n    }\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVSegment.h",
    "content": "//\n//  Segment.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"RVPoint.h\"\n#import \"RVSegmentConnection.h\"\n\n#import \"SegmentEnd.h\"\n\ntypedef struct SegmentTesselation {\n    GLKVector2 p;\n    GLKVector2 n;\n} SegmentTesselation;\n\n\ntypedef SegmentTesselation (^SegmentTesselator)(float t);\n\n\n@class RVEndPoint, RVControlPoint, RVAnchorPoint;\n\n@interface RVSegment : NSObject\n\n@property (nonatomic) NSUInteger colorIndex;\n\n- (RVEndPoint *)endPointAtSegmentEnd:(SegmentEnd)segmentEnd;\n- (RVControlPoint *)controlPointAtSegmentEnd:(SegmentEnd)segmentEnd;\n- (RVAnchorPoint *)anchorPointAtSegmentEnd:(SegmentEnd)segmentEnd;\n\n- (RVSegmentConnection *)connectionAtSegmentEnd:(SegmentEnd)segmentEnd;\n- (void)setConnection:(RVSegmentConnection *)conncetion atSegmentEnd:(SegmentEnd)segmentEnd;\n\n- (NSUInteger)modelTesselationSegments;\n- (NSUInteger)lineTesselationSegments;\n- (SegmentTesselator)tesselator;\n\n\n- (void)adjustAnchorPoints;\n\n- (float)hitSquareDistance:(GLKVector2)point;\n\n- (NSArray *)endPoints;\n- (NSArray *)controlPoints;\n- (NSArray *)anchorPoints;\n\n- (NSSet *)draggablePoints;\n\n- (NSSet *)allPoints;\n\n@end\n"
  },
  {
    "path": "Revolved/RVSegment.m",
    "content": "//\n//  Segment.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSegment.h\"\n#import \"Geometry.h\"\n\n#import \"RVEndPoint.h\"\n#import \"RVAnchorPoint.h\"\n#import \"RVControlPoint.h\"\n\n@implementation RVSegment\n{\n    __strong RVEndPoint *_endPoints[2];\n    __strong RVControlPoint *_controlPoints[2];\n    __strong RVAnchorPoint *_anchorPoints[2];\n    __strong RVSegmentConnection *_connections[2];\n}\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _endPoints[0] = [[RVEndPoint alloc] initWithSegment:self segmentEnd:SegmentEndFirst];\n        _endPoints[1] = [[RVEndPoint alloc] initWithSegment:self segmentEnd:SegmentEndSecond];\n        \n        _controlPoints[0] = [[RVControlPoint alloc] initWithSegment:self segmentEnd:SegmentEndFirst];\n        _controlPoints[1] = [[RVControlPoint alloc] initWithSegment:self segmentEnd:SegmentEndSecond];\n\n        _anchorPoints[0] = [[RVAnchorPoint alloc] initWithSegment:self segmentEnd:SegmentEndFirst];\n        _anchorPoints[1] = [[RVAnchorPoint alloc] initWithSegment:self segmentEnd:SegmentEndSecond];\n        \n        _anchorPoints[0].hasControlPoint = YES;\n        _anchorPoints[1].hasControlPoint = YES;\n        \n        [self adjustAnchorPoints];\n    }\n    return self;\n}\n\n#pragma mark - Getters n Setters\n\n- (RVEndPoint *)endPointAtSegmentEnd:(SegmentEnd)segmentEnd\n{\n    return _endPoints[segmentEnd];\n}\n\n- (RVControlPoint *)controlPointAtSegmentEnd:(SegmentEnd)segmentEnd\n{\n    return _controlPoints[segmentEnd];\n}\n\n- (RVAnchorPoint *)anchorPointAtSegmentEnd:(SegmentEnd)segmentEnd\n{\n    return _anchorPoints[segmentEnd];\n}\n\n- (RVSegmentConnection *)connectionAtSegmentEnd:(SegmentEnd)segmentEnd\n{\n    return _connections[segmentEnd];\n}\n\n- (void)setConnection:(RVSegmentConnection *)conncetion atSegmentEnd:(SegmentEnd)segmentEnd\n{\n    _connections[segmentEnd] = conncetion;\n}\n\n\n#pragma mark - Tesselation\n\n- (float)approxLength\n{\n    GLKVector2 a = _endPoints[0].position;\n    GLKVector2 b = _endPoints[1].position;\n    GLKVector2 p1 = _controlPoints[0].position;\n    GLKVector2 p2 = _controlPoints[1].position;\n    \n    static const float EpsSq = 0.0001f;\n    \n    if (SquareDistancePointSegment(a, b, p1) < EpsSq && SquareDistancePointSegment(a, b, p2) < EpsSq) {\n        return 0;\n    }\n    \n    float length = (GLKVector2Length(GLKVector2Subtract(a, p1)) +\n                    GLKVector2Length(GLKVector2Subtract(p1, p2)) +\n                    GLKVector2Length(GLKVector2Subtract(p2, b)));\n\n    return length;\n}\n\n- (NSUInteger)modelTesselationSegments\n{\n    float segments = [self approxLength]/0.18f;\n    \n    return segments == 0.0f ? 1 : ceilf(sqrt(segments * segments * 0.5 + 64.0));\n}\n\n- (NSUInteger)lineTesselationSegments;\n{\n    float segments = [self approxLength]/0.05f;\n    \n    return segments == 0.0f ? 1 : ceilf(sqrt(segments * segments * 0.6 + 225.0));\n}\n\n\n\n- (SegmentTesselator)tesselator\n{\n    GLKVector2 a = _endPoints[0].position;\n    GLKVector2 b = _endPoints[1].position;\n    GLKVector2 p1 = _controlPoints[0].position;\n    GLKVector2 p2 = _controlPoints[1].position;\n    \n    return ^(float t){\n        float nt = 1.0f - t;\n        \n        SegmentTesselation tess;\n        tess.p = GLKVector2Make(a.x * nt * nt * nt  +  3.0 * p1.x * nt * nt * t  +  3.0 * p2.x * nt * t * t  +  b.x * t * t * t,\n                                a.y * nt * nt * nt  +  3.0 * p1.y * nt * nt * t  +  3.0 * p2.y * nt * t * t  +  b.y * t * t * t);\n        \n        tess.n = GLKVector2Make(-3.0 * a.x * nt * nt  +  3.0 * p1.x * (1.0 - 4.0 * t + 3.0 * t * t)  +  3.0 * p2.x * (2.0 * t - 3.0 * t * t) + 3.0 * b.x * t * t,\n                                -3.0 * a.y * nt * nt  +  3.0 * p1.y * (1.0 - 4.0 * t + 3.0 * t * t)  +  3.0 * p2.y * (2.0 * t - 3.0 * t * t) + 3.0 * b.y * t * t);\n        \n        tess.n = GLKVector2Normalize(GLKVector2Make(-tess.n.y, tess.n.x));\n        \n        \n        return tess;\n    };\n}\n\n\n\n- (NSArray *)endPoints\n{\n    return @[_endPoints[0], _endPoints[1]];\n}\n\n- (NSArray *)controlPoints\n{\n    return @[_controlPoints[0], _controlPoints[1]];\n}\n\n- (NSArray *)anchorPoints\n{\n    return @[_anchorPoints[0], _anchorPoints[1]];\n}\n\n\n\n- (NSSet *)draggablePoints\n{\n    return [NSSet setWithObjects:_endPoints[0], _controlPoints[0], _controlPoints[1], _endPoints[1], nil];\n}\n\n- (NSSet *)allPoints\n{\n    return [NSSet setWithObjects:_endPoints[0], _controlPoints[0], _controlPoints[1], _endPoints[1], _anchorPoints[0], _anchorPoints[1], nil];\n}\n\n- (float)hitSquareDistance:(GLKVector2)point\n{\n    float best = INFINITY;\n    const NSUInteger tesselationSegments = 6;\n    SegmentTesselator tessalator = self.tesselator;\n    SegmentTesselation a = tessalator(0.0);\n    \n    for (int seg = 1; seg < tesselationSegments + 1; seg++) {\n        \n        SegmentTesselation b = tessalator((double)seg/(double)tesselationSegments);\n        float dist = SquareDistancePointSegment(a.p, b.p, point);\n        if (dist <= best) {\n            best = dist;\n        }\n        a = b;\n    }\n    \n    return best;\n}\n\n- (void)adjustAnchorPoints\n{\n    GLKVector2 diff = GLKVector2Subtract(_endPoints[1].position, _endPoints[0].position);\n    \n    _anchorPoints[0].position = GLKVector2Add(_endPoints[0].position, GLKVector2MultiplyScalar(diff, 1.0/3.0));\n    _anchorPoints[1].position = GLKVector2Add(_endPoints[0].position, GLKVector2MultiplyScalar(diff, 2.0/3.0));\n    \n    if ([_anchorPoints[0] hasControlPoint]) {\n        _controlPoints[0].position = _anchorPoints[0].position;\n    }\n\n    if ([_anchorPoints[1] hasControlPoint]) {\n        _controlPoints[1].position = _anchorPoints[1].position;\n    }\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVSegmentConnection.h",
    "content": "//\n//  RVSegmentConnection.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 11.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"SegmentEnd.h\"\n\n@class RVSegment, RVEndPoint;\n\n@interface RVSegmentConnection : NSObject\n\n@property (nonatomic, weak, readonly) RVSegment *a;\n@property (nonatomic, readonly) SegmentEnd aEnd;\n\n@property (nonatomic, weak, readonly) RVSegment *b;\n@property (nonatomic, readonly) SegmentEnd bEnd;\n\n\n- (BOOL)hasSegment:(RVSegment *)segment;\n- (BOOL)hasEndPoint:(RVEndPoint *)endPoint;\n\n- (RVSegment *)otherSegment:(RVSegment *)segment otherEnd:(SegmentEnd *)otherEnd;\n\n+ (void)connectSegment:(RVSegment *)segment bySegmentEnd:(SegmentEnd)segmentEnd toSegment:(RVSegment *)otherSegment atSegmentEnd:(SegmentEnd)otherSegmentEnd;\n+ (void)disconnectSegment:(RVSegment *)segment atSegmentEnd:(SegmentEnd)segmentEnd;\n\n@end\n"
  },
  {
    "path": "Revolved/RVSegmentConnection.m",
    "content": "//\n//  RVSegmentConnection.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 11.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSegmentConnection.h\"\n#import \"RVSegment.h\"\n#import \"RVEndPoint.h\"\n\n@implementation RVSegmentConnection\n\n- (id)init\n{\n    assert(NO);\n}\n\n+ (instancetype)conncetionWithSegment:(RVSegment *)segment segmentEnd:(SegmentEnd)segmentEnd otherSegment:(RVSegment *)otherSegment otherSegmentEnd:(SegmentEnd)otherSegmentEnd\n{\n    return [[self alloc] initWithSegment:segment segmentEnd:segmentEnd otherSegment:otherSegment otherSegmentEnd:otherSegmentEnd];\n}\n\n- (instancetype)initWithSegment:(RVSegment *)segment segmentEnd:(SegmentEnd)segmentEnd otherSegment:(RVSegment *)otherSegment otherSegmentEnd:(SegmentEnd)otherSegmentEnd\n{\n    self = [super init];\n    if (self) {\n        _a = segment;\n        _aEnd = segmentEnd;\n        \n        _b = otherSegment;\n        _bEnd = otherSegmentEnd;\n    }\n    return self;\n}\n\n- (BOOL)hasSegment:(RVSegment *)segment\n{\n    return segment == _a || segment == _b;\n}\n\n- (BOOL)hasEndPoint:(RVEndPoint *)endPoint\n{\n    return [_a endPointAtSegmentEnd:_aEnd] == endPoint || [_b endPointAtSegmentEnd:_bEnd] == endPoint;\n}\n\n- (RVSegment *)otherSegment:(RVSegment *)segment otherEnd:(SegmentEnd *)otherEnd\n{\n    assert([self hasSegment:segment]);\n    \n    if (otherEnd) {\n        *otherEnd = segment == _a ? _bEnd : _aEnd;\n    }\n    \n    return segment == _a ? _b : _a;\n}\n\n\n+ (void)connectSegment:(RVSegment *)segment bySegmentEnd:(SegmentEnd)segmentEnd toSegment:(RVSegment *)otherSegment atSegmentEnd:(SegmentEnd)otherSegmentEnd\n{\n    NSAssert(segment != otherSegment, @\"\");\n    \n    RVSegmentConnection *connection = [RVSegmentConnection conncetionWithSegment:segment segmentEnd:segmentEnd otherSegment:otherSegment otherSegmentEnd:otherSegmentEnd];\n    \n    [segment setConnection:connection atSegmentEnd:segmentEnd];\n    [otherSegment setConnection:connection atSegmentEnd:otherSegmentEnd];\n}\n\n+ (void)disconnectSegment:(RVSegment *)segment atSegmentEnd:(SegmentEnd)segmentEnd\n{\n    RVSegmentConnection *connection = [segment connectionAtSegmentEnd:segmentEnd];\n    \n    if (!connection) {\n        return;\n    }\n    \n    [connection.a setConnection:nil atSegmentEnd:connection.aEnd];\n    [connection.b setConnection:nil atSegmentEnd:connection.bEnd];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVSegmentsTutorialPage.h",
    "content": "//\n//  RVSegmentsTutorialPage.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialPage.h\"\n\n@interface RVSegmentsTutorialPage : RVTutorialPage\n\n@end\n"
  },
  {
    "path": "Revolved/RVSegmentsTutorialPage.m",
    "content": "//\n//  RVSegmentsTutorialPage.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSegmentsTutorialPage.h\"\n\n@interface RVSegmentsTutorialPage()\n\n@property (weak, nonatomic) IBOutlet UIImageView *firstSegmentImageView;\n@property (weak, nonatomic) IBOutlet UIImageView *secondSegmentImageView;\n@property (weak, nonatomic) IBOutlet UIImageView *thirdSegmentImageView;\n\n@end\n\n@implementation RVSegmentsTutorialPage\n\n\n- (NSString *)descriptionString\n{\n    return @\"In Revolved models consist of segments\";\n}\n\n- (void)setDisplayPercent:(float)displayPercent\n{\n    [super setDisplayPercent:displayPercent];\n    \n    \n    const CGFloat Offset = 440.0f;\n    \n    self.firstSegmentImageView.transform  = CGAffineTransformMakeTranslation(0.0f, -1 * Offset * [self progressForPercent:displayPercent*1.0]);\n    self.secondSegmentImageView.transform = CGAffineTransformMakeTranslation(0.0f, -2 * Offset * [self progressForPercent:displayPercent*1.0]);\n    self.thirdSegmentImageView.transform  = CGAffineTransformMakeTranslation(0.0f, -3 * Offset * [self progressForPercent:displayPercent*1.0]);\n}\n\n- (float)progressForPercent:(float)percent\n{\n    percent = MIN(MAX(0.0f, percent), 1.0f);\n\n    float value = - percent * (percent - 2.0f);\n    return MIN(MAX(0.0f, 1.0f - value), 1.0f);\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVSegmentsTutorialPage.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVSegmentsTutorialPage\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"576\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialSegment1\" id=\"cvr-zH-myr\">\n                    <rect key=\"frame\" x=\"192\" y=\"216\" width=\"316\" height=\"222\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialSegment2\" id=\"5WS-Bj-HsI\">\n                    <rect key=\"frame\" x=\"192\" y=\"166\" width=\"316\" height=\"238\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialSegment3\" id=\"F4A-fQ-EdV\">\n                    <rect key=\"frame\" x=\"226\" y=\"138\" width=\"248\" height=\"167\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <outlet property=\"firstSegmentImageView\" destination=\"cvr-zH-myr\" id=\"cV7-Vx-pzb\"/>\n                <outlet property=\"secondSegmentImageView\" destination=\"5WS-Bj-HsI\" id=\"EWk-Ne-HRe\"/>\n                <outlet property=\"thirdSegmentImageView\" destination=\"F4A-fQ-EdV\" id=\"OeM-LM-wjP\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TutorialSegment1\" width=\"632\" height=\"444\"/>\n        <image name=\"TutorialSegment2\" width=\"632\" height=\"476\"/>\n        <image name=\"TutorialSegment3\" width=\"496\" height=\"334\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVSelectTutorialPage.h",
    "content": "//\n//  RVSelectTutorialPage.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialPage.h\"\n\n@interface RVSelectTutorialPage : RVTutorialPage\n\n@end\n"
  },
  {
    "path": "Revolved/RVSelectTutorialPage.m",
    "content": "//\n//  RVSelectTutorialPage.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSelectTutorialPage.h\"\n\n@interface RVSelectTutorialPage()\n@property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *points;\n@property (weak, nonatomic) IBOutlet UIImageView *rotatedControlPoint;\n\n@end\n\n\n@implementation RVSelectTutorialPage\n\n- (void)setDisplayPercent:(float)displayPercent\n{\n    [super setDisplayPercent:displayPercent];\n    \n    \n    float progress = [self progressForPercent:displayPercent];\n    float alpha = 0.3 + 0.7 * progress;\n    float scale = 0.01 + 0.99 * progress;\n    CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);\n    \n    for (UIView *point in self.points) {\n        point.alpha = alpha;\n        if (point == _rotatedControlPoint) {\n            point.transform = CGAffineTransformRotate(transform, M_PI_2);\n        } else {\n            point.transform = transform;\n        }\n    }\n}\n\n- (NSString *)descriptionString\n{\n    return @\"After selecting a segment with a tap...\";\n}\n\n- (float)progressForPercent:(float)percent\n{\n    return MIN(MAX(0.0, (percent - 0.2)/0.8), 1.0);\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVSelectTutorialPage.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVSelectTutorialPage\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"576\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialLineLong\" id=\"cvr-zH-myr\">\n                    <rect key=\"frame\" x=\"263\" y=\"158\" width=\"174\" height=\"260\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialEndPoint\" id=\"SOh-2C-Sar\">\n                    <rect key=\"frame\" x=\"239\" y=\"133\" width=\"52\" height=\"52\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialEndPoint\" id=\"5DR-ga-dv8\">\n                    <rect key=\"frame\" x=\"408\" y=\"390\" width=\"52\" height=\"52\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialControlPoint\" id=\"hPR-Ye-xwx\">\n                    <rect key=\"frame\" x=\"355\" y=\"309\" width=\"44\" height=\"44\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialControlPoint\" id=\"1m4-AS-RQz\">\n                    <rect key=\"frame\" x=\"299\" y=\"222\" width=\"44\" height=\"44\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <outlet property=\"rotatedControlPoint\" destination=\"1m4-AS-RQz\" id=\"C5J-K8-mau\"/>\n                <outletCollection property=\"points\" destination=\"5DR-ga-dv8\" id=\"XZR-Mc-nWb\"/>\n                <outletCollection property=\"points\" destination=\"hPR-Ye-xwx\" id=\"Zl2-Cm-shr\"/>\n                <outletCollection property=\"points\" destination=\"1m4-AS-RQz\" id=\"uUi-kk-2VX\"/>\n                <outletCollection property=\"points\" destination=\"SOh-2C-Sar\" id=\"Von-tI-bMt\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TutorialControlPoint\" width=\"88\" height=\"88\"/>\n        <image name=\"TutorialEndPoint\" width=\"104\" height=\"104\"/>\n        <image name=\"TutorialLineLong\" width=\"348\" height=\"520\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVSettingsButtonsView.h",
    "content": "//\n//  RVSettingsButtonsView.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVSettingsButtonsView : UIView\n\n@property (weak, nonatomic) IBOutlet UIButton *tutorialButton;\n@property (weak, nonatomic) IBOutlet UIButton *creditsButton;\n@property (weak, nonatomic) IBOutlet UIButton *rateMeButton;\n\n@property (weak, nonatomic) IBOutlet UIButton *settingsButton;\n\n@property (nonatomic) BOOL out;\n- (void)setOut:(BOOL)isOut animated:(BOOL)animated;\n\n@end\n"
  },
  {
    "path": "Revolved/RVSettingsButtonsView.m",
    "content": "//\n//  RVSettingsButtonsView.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSettingsButtonsView.h\"\n\nstatic const CGFloat Radius = 59.0f;\nstatic const CGFloat Angle = M_PI/3.5;\n\n@interface RVSettingsButtonsView()\n\n@property (weak, nonatomic) IBOutlet UIView *container;\n\n@end\n\n\n@implementation RVSettingsButtonsView\n\n- (void)awakeFromNib\n{\n    self.tutorialButton.exclusiveTouch = YES;\n    self.creditsButton.exclusiveTouch = YES;\n    self.rateMeButton.exclusiveTouch = YES;\n    self.settingsButton.exclusiveTouch = YES;\n    \n    CGSize size = self.container.bounds.size;\n    \n    CGFloat dx = roundf(Radius * sinf(Angle));\n    CGFloat dy = roundf(Radius * cosf(Angle));\n    \n    \n    self.tutorialButton.center = CGPointMake(size.width/2.0 - dx, size.width/2.0 - dy);\n    self.creditsButton.center = CGPointMake(size.width/2.0, size.width/2.0 - Radius);\n    self.rateMeButton.center = CGPointMake(size.width/2.0 + dx, size.width/2.0 - dy);\n\n    [self setOut:NO];\n}\n\n- (IBAction)buttonTapped:(UIButton *)sender\n{\n    [self setOut:!self.out animated:YES];\n}\n\n\n- (void)setOut:(BOOL)out\n{\n    [self setOut:out animated:NO];\n}\n\n- (void)setOut:(BOOL)isOut animated:(BOOL)animated\n{\n    NSTimeInterval duration = 0.5;\n    CGFloat damping = 0.8f;\n    CGFloat velocity = -1.0f;\n    \n    const CGFloat AlmostPi = M_PI*0.999f;\n    const CGFloat AlmostZero = 0.0f;\n\n    self.settingsButton.userInteractionEnabled = NO;\n    [UIView animateWithDuration:animated ? duration : 0.0f delay:0.0 usingSpringWithDamping:damping initialSpringVelocity:velocity options:UIViewAnimationOptionAllowUserInteraction animations:^{\n        self.container.transform = CGAffineTransformMakeRotation(isOut ? AlmostZero : AlmostPi);\n        self.tutorialButton.transform = CGAffineTransformMakeRotation(isOut ? AlmostZero : -AlmostPi);\n        self.creditsButton.transform = CGAffineTransformMakeRotation(isOut ? AlmostZero : -AlmostPi);\n        self.rateMeButton.transform = CGAffineTransformMakeRotation(isOut ? AlmostZero : -AlmostPi);\n    } completion:^(BOOL finished) {\n        self.settingsButton.userInteractionEnabled = YES;\n        \n        if (finished && !isOut) {\n            self.container.transform = CGAffineTransformMakeRotation(-AlmostPi);\n            self.tutorialButton.transform = CGAffineTransformMakeRotation(AlmostPi);\n            self.creditsButton.transform = CGAffineTransformMakeRotation(AlmostPi);\n            self.rateMeButton.transform = CGAffineTransformMakeRotation(AlmostPi);\n        }\n    }];\n    \n    self.tutorialButton.userInteractionEnabled = isOut;\n    self.creditsButton.userInteractionEnabled = isOut;\n    self.rateMeButton.userInteractionEnabled = isOut;\n    \n    _out = isOut;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVSettingsButtonsView.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVSettingsButtonsView\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"240\" height=\"240\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"BNa-6a-HEk\" userLabel=\"Container\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"-22\" width=\"240\" height=\"240\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                    <subviews>\n                        <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"mbI-FI-ulT\">\n                            <rect key=\"frame\" x=\"95\" y=\"95\" width=\"50\" height=\"50\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                            <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                            <state key=\"normal\" image=\"Gear\"/>\n                            <connections>\n                                <action selector=\"buttonTapped:\" destination=\"1\" eventType=\"touchUpInside\" id=\"ti1-zu-NWe\"/>\n                            </connections>\n                        </button>\n                        <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"IvU-Ws-yGJ\">\n                            <rect key=\"frame\" x=\"95\" y=\"21\" width=\"50\" height=\"50\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                            <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                            <state key=\"normal\" image=\"CreditsButton\"/>\n                        </button>\n                        <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"kYz-Ic-neV\">\n                            <rect key=\"frame\" x=\"154\" y=\"43\" width=\"50\" height=\"50\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                            <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                            <state key=\"normal\" image=\"RateButton\"/>\n                        </button>\n                        <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"Rkz-uZ-DSj\">\n                            <rect key=\"frame\" x=\"38\" y=\"43\" width=\"50\" height=\"50\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMinX=\"YES\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\" flexibleMaxY=\"YES\"/>\n                            <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                            <state key=\"normal\" image=\"TutorialButton\"/>\n                        </button>\n                    </subviews>\n                </view>\n            </subviews>\n            <connections>\n                <outlet property=\"container\" destination=\"BNa-6a-HEk\" id=\"Cpo-8l-Q2c\"/>\n                <outlet property=\"creditsButton\" destination=\"IvU-Ws-yGJ\" id=\"8ZS-8a-Jce\"/>\n                <outlet property=\"rateMeButton\" destination=\"kYz-Ic-neV\" id=\"U8y-lL-cBc\"/>\n                <outlet property=\"settingsButton\" destination=\"mbI-FI-ulT\" id=\"xSe-CS-YG9\"/>\n                <outlet property=\"tutorialButton\" destination=\"Rkz-uZ-DSj\" id=\"SxW-gL-Q5T\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"CreditsButton\" width=\"26\" height=\"28\"/>\n        <image name=\"Gear\" width=\"32\" height=\"32\"/>\n        <image name=\"RateButton\" width=\"34\" height=\"22\"/>\n        <image name=\"TutorialButton\" width=\"28\" height=\"28\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVSpaceConverter.h",
    "content": "//\n//  SpaceConverter.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface RVSpaceConverter : NSObject\n\n- (id)initWithViewSize:(CGSize)viewSize;\n\n- (GLKVector2)modelPointForViewPoint:(CGPoint)viewPoint;\n- (GLKVector2)modelVectorForViewVector:(CGPoint)viewVector;\n- (CGPoint)viewPointForModelPoint:(GLKVector2)modelPoint;\n\n- (float)modelSquareDistanceForViewDistance:(CGFloat)viewDistance;\n\n@end\n"
  },
  {
    "path": "Revolved/RVSpaceConverter.m",
    "content": "//\n//  SpaceConverter.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 07.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSpaceConverter.h\"\n#import \"Geometry.h\"\n\nstatic const float Scale = 2.0;\n\nstatic const float AxisLocation = 30.0f;\n\n@implementation RVSpaceConverter\n{\n    CGSize _viewSize;\n}\n\n- (id)initWithViewSize:(CGSize)viewSize\n{\n    self = [super init];\n    if (self) {\n        _viewSize = viewSize;\n    }\n    return self;\n}\n\n- (GLKVector2)modelPointForViewPoint:(CGPoint)viewPoint\n{\n    GLKVector2 point = GLKVector2Make(viewPoint.x, viewPoint.y);\n    point.y -= _viewSize.height/2.0;\n    point.y *= -1.0;\n    point.x -= AxisLocation;\n    \n    point = GLKVector2MultiplyScalar(point, Scale * 2.0/_viewSize.height);\n    \n    return point;\n}\n\n- (GLKVector2)modelVectorForViewVector:(CGPoint)viewVector\n{\n    GLKVector2 start = [self modelPointForViewPoint:CGPointZero];\n    GLKVector2 end = [self modelPointForViewPoint:viewVector];\n    \n    return GLKVector2Subtract(end, start);\n}\n\n- (CGPoint)viewPointForModelPoint:(GLKVector2)modelPoint\n{\n    GLKVector2 point;\n    point = GLKVector2MultiplyScalar(modelPoint, _viewSize.height / (Scale * 2.0));\n    point.x += AxisLocation;\n    point.y *= -1.0;\n    point.y += _viewSize.height/2.0;\n    \n    return CGPointMake(point.x, point.y);\n}\n\n- (float)modelSquareDistanceForViewDistance:(CGFloat)viewDistance\n{\n    GLKVector2 a = [self modelPointForViewPoint:CGPointMake(0.0, 0.0)];\n    GLKVector2 b = [self modelPointForViewPoint:CGPointMake(viewDistance, 0.0)];\n    \n    return GLKVector2DistanceSq(b, a);\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVSprite.h",
    "content": "//\n//  RVSprite.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 19.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@class RVAnimation;\n@interface RVSprite : NSObject\n\n@property (nonatomic) GLuint indiciesOffset;\n@property (nonatomic) GLuint indiciesCount;\n\n- (void)addAnimation:(RVAnimation *)animation forKey:(NSString *)key;\n- (RVAnimation *)animationForKey:(NSString *)key;\n- (void)removeAnimationForKey:(NSString *)key;\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVSprite.m",
    "content": "//\n//  RVSprite.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 19.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVSprite.h\"\n#import \"RVAnimator.h\"\n#import \"RVAnimation_Private.h\"\n\n@implementation RVSprite\n\n- (void)addAnimation:(RVAnimation *)animation forKey:(NSString *)key\n{\n    [[RVAnimator sharedAnimator] addAnimation:animation forKey:key toTarget:self];\n}\n\n- (RVAnimation *)animationForKey:(NSString *)key\n{\n    return [[RVAnimator sharedAnimator] animationforKey:key forTarget:self];\n}\n\n- (void)removeAnimationForKey:(NSString *)key\n{\n    [[RVAnimator sharedAnimator] removeAnimationForKey:key fromTarget:self];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVStartTutorialPage.h",
    "content": "//\n//  RVStartTutorialPage.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialPage.h\"\n\n@interface RVStartTutorialPage : RVTutorialPage\n\n@end\n"
  },
  {
    "path": "Revolved/RVStartTutorialPage.m",
    "content": "//\n//  RVStartTutorialPage.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 02.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVStartTutorialPage.h\"\n\n@interface RVStartTutorialPage()\n\n@property (weak, nonatomic) IBOutlet UIImageView *getToKnow;\n@property (weak, nonatomic) IBOutlet UIImageView *logo;\n@property (weak, nonatomic) IBOutlet UIImageView *wheel;\n\n@end\n\n@implementation RVStartTutorialPage\n\n- (void)setDisplayPercent:(float)displayPercent\n{\n    [super setDisplayPercent:displayPercent];\n\n    self.wheel.transform = CGAffineTransformMakeRotation(-(displayPercent - 1.0f) * 2.0 * M_PI);\n    displayPercent = MIN(MAX(0.0f, displayPercent), 1.0f);\n    \n    const CGFloat Offset = 500.0f;\n    \n    self.getToKnow.transform = CGAffineTransformMakeTranslation(0.0f, -Offset * (1.0f + displayPercent * (displayPercent - 2.0)));\n\n    displayPercent -= 0.5;\n    displayPercent *= 2.0f;\n    displayPercent = MIN(MAX(0.0f, displayPercent), 1.0f);\n\n    self.logo.alpha = displayPercent;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVStartTutorialPage.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"1\" customClass=\"RVStartTutorialPage\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"700\" height=\"576\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"Logo\" id=\"alZ-5r-zMo\">\n                    <rect key=\"frame\" x=\"200\" y=\"261\" width=\"300\" height=\"54\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialGetToKnow\" id=\"8et-sW-I62\">\n                    <rect key=\"frame\" x=\"253\" y=\"212\" width=\"195\" height=\"35\"/>\n                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                </imageView>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"TutorialWheel\" id=\"IJS-dj-Nqo\">\n                    <rect key=\"frame\" x=\"324\" y=\"510\" width=\"52\" height=\"52\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <connections>\n                <outlet property=\"getToKnow\" destination=\"8et-sW-I62\" id=\"O5a-ek-CzJ\"/>\n                <outlet property=\"logo\" destination=\"alZ-5r-zMo\" id=\"ODx-hh-A8G\"/>\n                <outlet property=\"wheel\" destination=\"IJS-dj-Nqo\" id=\"DmO-ao-T7F\"/>\n            </connections>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"Logo\" width=\"300\" height=\"54\"/>\n        <image name=\"TutorialGetToKnow\" width=\"195\" height=\"35\"/>\n        <image name=\"TutorialWheel\" width=\"104\" height=\"104\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVTutorialLineImageView.h",
    "content": "//\n//  RVTutorialLineImageView.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVTutorialLineImageView : UIImageView\n\n- (void)positionFromPoint:(CGPoint)from toPoint:(CGPoint)to;\n- (void)positionWithRotation:(CGFloat)rotation atPoint:(CGPoint)point;\n\n@end\n"
  },
  {
    "path": "Revolved/RVTutorialLineImageView.m",
    "content": "//\n//  RVTutorialLineImageView.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 01.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialLineImageView.h\"\n\n@implementation RVTutorialLineImageView\n\n- (void)awakeFromNib\n{\n    self.image = [[UIImage imageNamed:@\"TutorialLine\"] resizableImageWithCapInsets:UIEdgeInsetsMake(2, 2, 2, 2)];\n    [self positionFromPoint:self.center toPoint:self.center];\n}\n\n/*\n I shouldn't really modify self, but this is much more convenient\n */\n- (void)positionFromPoint:(CGPoint)from toPoint:(CGPoint)to\n{\n    const CGFloat LengthSurplus = 3.0f;\n    \n    CGFloat dx = to.x - from.x;\n    CGFloat dy = to.y - from.y;\n    \n    CGFloat length = sqrtf(dx * dx + dy * dy);\n    \n    self.bounds = CGRectMake(0.0f, 0.0f, length + 2.0 * LengthSurplus, 6.0f);\n    self.center = CGPointMake(from.x + dx/2.0f, from.y + dy/2.0f);\n    self.transform = CGAffineTransformMakeRotation(atan2f(dy, dx));\n}\n\n- (void)positionWithRotation:(CGFloat)rotation atPoint:(CGPoint)point\n{\n    self.bounds = CGRectMake(0.0, 0.0, 6.0f, 6.0f);\n    self.center = point;\n    self.transform = CGAffineTransformMakeRotation(rotation);\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVTutorialPage.h",
    "content": "//\n//  RVTutorialPageCell.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 21.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVTutorialPage : UIView\n\n@property (nonatomic) float displayPercent;\n\n- (void)setupInterfaceOrientation:(UIInterfaceOrientation)orientation;\n- (NSString *)descriptionString;\n\n\n@end\n"
  },
  {
    "path": "Revolved/RVTutorialPage.m",
    "content": "//\n//  RVTutorialPageCell.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 21.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialPage.h\"\n\nconst CGFloat LabelHeight = 50.0f;\n\n@interface RVTutorialPage()\n\n@property (nonatomic, strong) UILabel *label;\n\n@end\n\n\n@implementation RVTutorialPage\n\n- (void)awakeFromNib\n{\n    [super awakeFromNib];\n    self.clipsToBounds = YES;\n    self.backgroundColor = [UIColor rv_backgroundColor];\n    \n    self.label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, self.bounds.size.height - LabelHeight, self.bounds.size.width, LabelHeight)];\n    self.label.backgroundColor = [UIColor colorWithWhite:0.05 alpha:0.85];\n    self.label.textColor = [UIColor whiteColor];\n    self.label.text = [self descriptionString];\n    self.label.textAlignment = NSTextAlignmentCenter;\n    if (![self.label.text length]) {\n        self.label.hidden = YES;\n    }\n        \n    [self addSubview:self.label];\n}\n\n- (void)setDisplayPercent:(float)displayPercent\n{\n    _displayPercent = displayPercent;\n    \n    self.hidden = displayPercent > 3.3 || displayPercent < -1.3;\n\n    displayPercent -= 1.0f;\n    \n    const float Span = 0.3;\n    \n    if (displayPercent > Span) {\n        displayPercent -= Span;\n        displayPercent *= -1.0f;\n        displayPercent += 1.0f;\n    } else if ( displayPercent < -Span) {\n        displayPercent += 1.0 + Span;\n    } else {\n        displayPercent = 1.0f;\n    }\n}\n\n\n- (void)setupInterfaceOrientation:(UIInterfaceOrientation)orientation\n{\n    \n}\n\n- (NSString *)descriptionString\n{\n    return @\"\";\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVTutorialScrollView.h",
    "content": "//\n//  RVTutorialScrollView.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 08.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVTutorialScrollView : UIScrollView\n\n@end\n"
  },
  {
    "path": "Revolved/RVTutorialScrollView.m",
    "content": "//\n//  RVTutorialScrollView.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 08.10.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialScrollView.h\"\n\n@implementation RVTutorialScrollView\n\n- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event\n{\n    return YES;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVTutorialViewController.h",
    "content": "//\n//  RVTutorialViewController.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 21.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface RVTutorialViewController : UIViewController\n\n- (void)presentWithPostDismissalBlock:(void (^)(void))postDismissalBlock;\n\n@end\n"
  },
  {
    "path": "Revolved/RVTutorialViewController.m",
    "content": "//\n//  RVTutorialViewController.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 21.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVTutorialViewController.h\"\n#import \"RVTutorialPage.h\"\n#import \"RVFinishTutorialPage.h\"\n\n#import \"RVPassForwardView.h\"\n\n#import \"RVFloatAnimation.h\"\n#import \"RVAnimator.h\"\n#import \"RVUserDefaults.h\"\n\n#import \"UIView+RotationAnimation.h\"\n\nstatic const CGSize PageSize = {700.0f, 576.0f};\nstatic const CGFloat PageSpace = 120.0f;\n\n@interface RVTutorialViewController () <UIScrollViewDelegate>\n@property (weak, nonatomic) IBOutlet RVPassForwardView *backgroundView;\n@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;\n@property (weak, nonatomic) IBOutlet UIPageControl *pageIndicator;\n@property (weak, nonatomic) IBOutlet UIButton *closeButton;\n@property (nonatomic, strong) NSArray *pages;\n\n@property (nonatomic, copy) void (^postDismissalBlock)(void);\n\n@end\n\n@implementation RVTutorialViewController\n\n- (void)viewDidLoad\n{\n    [super viewDidLoad];\n    \n    [self.backgroundView setForwardView:self.scrollView];\n    \n    self.backgroundView.backgroundColor = [UIColor rv_dimColor];\n    \n    self.pages = @[\n                   [[NSBundle mainBundle] loadNibNamed:@\"RVStartTutorialPage\" owner:self options:nil][0],\n                   [[NSBundle mainBundle] loadNibNamed:@\"RVSegmentsTutorialPage\" owner:self options:nil][0],\n                   [[NSBundle mainBundle] loadNibNamed:@\"RVDrawingTutorialPage\" owner:self options:nil][0],\n                   [[NSBundle mainBundle] loadNibNamed:@\"RVRevolvedTutorialPage\" owner:self options:nil][0],\n                   [[NSBundle mainBundle] loadNibNamed:@\"RVRevolvedTutorialPageSolid\" owner:self options:nil][0],\n                   [[NSBundle mainBundle] loadNibNamed:@\"RVSelectTutorialPage\" owner:self options:nil][0],\n                   [[NSBundle mainBundle] loadNibNamed:@\"RVBendTutorialPage\" owner:self options:nil][0],\n                   [[NSBundle mainBundle] loadNibNamed:@\"RVFinishTutorialPage\" owner:self options:nil][0],\n                   ];\n    \n    self.pageIndicator.numberOfPages = self.pages.count;\n    \n    [[(RVFinishTutorialPage *)[self.pages lastObject] button] addTarget:self action:@selector(closeTapped:) forControlEvents:UIControlEventTouchUpInside];\n    \n    self.scrollView.frame = CGRectMake(0.0f, 0.0f, PageSpace + PageSize.width, self.view.bounds.size.height);\n    self.scrollView.center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds));\n    self.scrollView.clipsToBounds = NO;\n    self.scrollView.contentSize = CGSizeMake(self.pages.count * (PageSize.width + PageSpace), 1.0f);\n    self.scrollView.delegate = self;\n    self.scrollView.delaysContentTouches = NO;\n    \n    [self.pages enumerateObjectsUsingBlock:^(RVTutorialPage *page , NSUInteger idx, BOOL *stop) {\n        [self.scrollView addSubview:page];\n        page.center = CGPointMake((idx + 0.5f) * (PageSize.width + PageSpace), self.scrollView.bounds.size.height/2.0f);\n        [page setupInterfaceOrientation:self.interfaceOrientation];\n    }];\n    \n    \n    if (![[NSUserDefaults standardUserDefaults] boolForKey:HasPlayedTutorialKey]) {\n\n        UIView *lastPage = [self.pages lastObject];\n        UIButton *button = self.closeButton;\n        [button removeFromSuperview];\n\n        button.center = CGPointMake(lastPage.center.x + lastPage.bounds.size.width/2.0 + 80.0, lastPage.center.y);\n        [self.scrollView addSubview:button];\n    }\n}\n\n\n\n- (void)rv_setRotation:(float)rotation\n{\n    self.scrollView.contentOffset = CGPointMake(rotation, 0.0f);\n}\n\n- (float)rv_Rotation\n{\n    return self.scrollView.contentOffset.x;\n}\n\n- (void)presentWithPostDismissalBlock:(void (^)(void))postDismissalBlock\n{\n    self.postDismissalBlock = postDismissalBlock;\n    \n    const NSTimeInterval BackgroundDuration = 0.3;\n    const float StartOffset = - 900.0f;\n    \n    self.view.hidden = NO;\n    self.backgroundView.alpha = 0.0f;\n    [self.scrollView setContentOffset:CGPointMake(StartOffset, 0.0f)];\n\n    [UIView animateWithDuration:BackgroundDuration animations:^{\n        self.backgroundView.alpha = 1.0f;\n    } completion:^(BOOL finished) {\n\n        self.backgroundView.userInteractionEnabled = NO;\n        RVFloatAnimation *animation = [RVFloatAnimation floatAnimationFromValue:StartOffset toValue:0.0f withDuration:0.6f];\n        animation.animationCurve = RVAnimationCurveQuartEaseOut;\n        animation.completionBlock = ^{self.backgroundView.userInteractionEnabled = YES;};\n        \n        [[RVAnimator sharedAnimator] addAnimation:animation forKey:@\"rotation\" toTarget:self];\n    \n    }];\n}\n\n- (void)dismiss\n{\n    const NSTimeInterval BackgroundDuration = 0.2;\n    const NSTimeInterval SlideDuration = 0.3;\n    \n    self.view.userInteractionEnabled = NO;\n    \n    [ UIView animateWithDuration:SlideDuration delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{\n        self.scrollView.transform = CGAffineTransformMakeTranslation(0.0f, self.view.bounds.size.height);\n        self.pageIndicator.alpha = 0.0f;\n        self.closeButton.alpha = 0.0f;\n    } completion:^(BOOL finished) {\n        [UIView animateWithDuration:BackgroundDuration delay:0.0 options:0 animations:^{\n            self.backgroundView.alpha = 0.0f;\n        } completion:^(BOOL finished) {\n            self.postDismissalBlock();\n            self.postDismissalBlock = nil;\n        }];\n    }];\n\n}\n\n- (void)scrollViewDidScroll:(UIScrollView *)scrollView\n{\n    CGFloat span = scrollView.bounds.size.width/2.0f;\n    CGFloat center = scrollView.contentOffset.x + span;\n\n    [self.pages enumerateObjectsUsingBlock:^(RVTutorialPage *page , NSUInteger idx, BOOL *stop) {\n        float percent = 1.0f - (page.center.x - center)/span;\n        page.displayPercent = percent;\n        if (percent >= 0.0 && percent <= 2.0) {\n            self.pageIndicator.currentPage = idx;\n        }\n    }];\n}\n\n\n- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration\n{\n    [self.pages enumerateObjectsUsingBlock:^(RVTutorialPage *page , NSUInteger idx, BOOL *stop) {\n        [page setupInterfaceOrientation:toInterfaceOrientation];\n    }];\n}\n\n- (IBAction)closeTapped:(UIButton *)sender\n{\n    [self dismiss];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/RVTutorialViewController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB\" version=\"3.0\" toolsVersion=\"4510\" systemVersion=\"12E55\" targetRuntime=\"iOS.CocoaTouch.iPad\" propertyAccessControl=\"none\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"3742\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"RVTutorialViewController\">\n            <connections>\n                <outlet property=\"backgroundView\" destination=\"XYo-bF-GVu\" id=\"Jkm-F9-FT2\"/>\n                <outlet property=\"closeButton\" destination=\"bA7-0D-2wT\" id=\"pkR-BZ-ZtX\"/>\n                <outlet property=\"pageIndicator\" destination=\"BYY-YD-edg\" id=\"Sub-up-AMm\"/>\n                <outlet property=\"scrollView\" destination=\"5k7-gM-S5R\" id=\"Jy8-Kk-oFC\"/>\n                <outlet property=\"view\" destination=\"2\" id=\"3\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view clearsContextBeforeDrawing=\"NO\" contentMode=\"scaleToFill\" id=\"2\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" id=\"XYo-bF-GVu\" userLabel=\"Bcakground View\" customClass=\"RVPassForwardView\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                    <subviews>\n                        <scrollView clipsSubviews=\"YES\" contentMode=\"scaleToFill\" showsHorizontalScrollIndicator=\"NO\" id=\"5k7-gM-S5R\" customClass=\"RVTutorialScrollView\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"62\" width=\"1024\" height=\"463\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        </scrollView>\n                        <pageControl opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" numberOfPages=\"3\" id=\"BYY-YD-edg\">\n                            <rect key=\"frame\" x=\"493\" y=\"699\" width=\"39\" height=\"37\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                        </pageControl>\n                        <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" adjustsImageWhenHighlighted=\"NO\" lineBreakMode=\"middleTruncation\" id=\"bA7-0D-2wT\">\n                            <rect key=\"frame\" x=\"490\" y=\"30\" width=\"44\" height=\"44\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                            <state key=\"normal\" image=\"TutorialCloseButton\"/>\n                            <connections>\n                                <action selector=\"closeTapped:\" destination=\"-1\" eventType=\"touchUpInside\" id=\"hCD-f6-Gei\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                </view>\n            </subviews>\n            <simulatedStatusBarMetrics key=\"simulatedStatusBarMetrics\" statusBarStyle=\"lightContent\"/>\n            <simulatedOrientationMetrics key=\"simulatedOrientationMetrics\" orientation=\"landscapeRight\"/>\n            <simulatedScreenMetrics key=\"simulatedDestinationMetrics\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"TutorialCloseButton\" width=\"44\" height=\"44\"/>\n    </resources>\n</document>"
  },
  {
    "path": "Revolved/RVUserDefaults.h",
    "content": "//\n//  RVUserDefaults.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 19.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n\nextern NSString * const HasImportedStartModelsKey;\nextern NSString * const HasPlayedTutorialKey;\nextern NSString * const LastUsedColorIndexKey;\nextern NSString * const LastUsedModelIndexKey;\n\n"
  },
  {
    "path": "Revolved/RVUserDefaults.m",
    "content": "//\n//  RVUserDefaults.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 19.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n\nNSString * const HasImportedStartModelsKey = @\"HasImportedStartModels\";\nNSString * const HasPlayedTutorialKey = @\"HasPlayedTutorial\";\nNSString * const LastUsedColorIndexKey = @\"LastUsedColor\";\nNSString * const LastUsedModelIndexKey = @\"LastUsedModel\";"
  },
  {
    "path": "Revolved/RVVectorAnimation.h",
    "content": "//\n//  RVColorAnimation.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVAnimation.h\"\n\n@interface RVVectorAnimation : RVAnimation\n\n@property (nonatomic) GLKVector3 from;\n@property (nonatomic) GLKVector3 to;\n\n- (GLKVector3)valueForProgress:(float)progress;\n+ (RVVectorAnimation *)vectorAnimationFromValue:(GLKVector3)fromValue toValue:(GLKVector3)toValue withDuration:(NSTimeInterval)duration;\n\n@end\n"
  },
  {
    "path": "Revolved/RVVectorAnimation.m",
    "content": "//\n//  RVColorAnimation.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 25.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"RVVectorAnimation.h\"\n\n@implementation RVVectorAnimation\n\n- (GLKVector3)valueForProgress:(float)progress\n{\n    return GLKVector3Add(GLKVector3MultiplyScalar(_to, progress), GLKVector3MultiplyScalar(_from, 1.0f - progress));\n}\n\n+ (RVVectorAnimation *)vectorAnimationFromValue:(GLKVector3)fromValue toValue:(GLKVector3)toValue withDuration:(NSTimeInterval)duration\n{\n    RVVectorAnimation *colorAnimation = [RVVectorAnimation new];\n    colorAnimation.from = fromValue;\n    colorAnimation.to = toValue;\n    colorAnimation.duration = duration;\n    \n    return colorAnimation;\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/Renderer.h",
    "content": "//\n//  Renderer.h\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@class Camera, RVModelMeshController, RVAxisMeshController, RVLineMeshController, RVPointMeshController, RVGuidlineDotMeshController;\n\n@interface Renderer : NSObject\n\n@property (nonatomic, strong) Camera *camera;\n@property (nonatomic, strong) RVModelMeshController *modelController;\n@property (nonatomic, strong) RVAxisMeshController *axisController;\n@property (nonatomic) CGRect meshViewport;\n\n\n@property (nonatomic, strong) RVGuidlineDotMeshController *guidlineController;\n@property (nonatomic, strong) RVLineMeshController *lineController;\n@property (nonatomic, strong) RVPointMeshController *pointController;\n@property (nonatomic) CGRect drawingViewport;\n@property (nonatomic) GLKMatrix4 drawingTransformMatrix;\n\n- (void)setupOpenGL;\n\n- (void)render;\n- (void)renderModelMesh;\n\n\n@end\n"
  },
  {
    "path": "Revolved/Renderer.m",
    "content": "//\n//  Renderer.m\n//  Patterns\n//\n//  Created by Bartosz Ciechanowski on 23.07.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"Renderer.h\"\n#import \"Camera.h\"\n\n#import \"RVModelShader.h\"\n#import \"RVAxisShader.h\"\n#import \"RVLineShader.h\"\n#import \"RVPointShader.h\"\n\n#import \"RVModelMeshController.h\"\n#import \"RVAxisMeshController.h\"\n#import \"RVGuidlineDotMeshController.h\"\n#import \"RVLineMeshController.h\"\n#import \"RVPointMeshController.h\"\n#import \"RVColorProvider.h\"\n\n#import \"RVModelSprite.h\"\n#import \"RVAxisSprite.h\"\n\n#import \"Constants.h\"\n\n@interface Renderer()\n\n@property (nonatomic, strong) RVModelShader *modelShader;\n@property (nonatomic, strong) RVAxisShader *axisShader;\n@property (nonatomic, strong) RVLineShader *lineShader;\n@property (nonatomic, strong) RVPointShader *pointShader;\n\n@property (nonatomic, strong) GLKTextureInfo *spritesTexture;\n@property (nonatomic, assign) GLuint noiseTextureName;\n@end\n\n\n@implementation Renderer\n\n- (id)init\n{\n    self = [super init];\n    if (self) {\n        _modelShader = [RVModelShader new];\n        _axisShader = [RVAxisShader new];\n        _lineShader = [RVLineShader new];\n        _pointShader = [RVPointShader new];\n    }\n    \n    return self;\n}\n\n- (void)setupOpenGL\n{\n    [self.modelShader loadProgram];\n    [self.axisShader loadProgram];\n    [self.lineShader loadProgram];\n    [self.pointShader loadProgram];\n    \n    NSError *error;\n    self.spritesTexture = [GLKTextureLoader textureWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@\"sprites\" ofType:@\"png\"]\n                                                              options:@{GLKTextureLoaderApplyPremultiplication: @(NO)}\n                                                                error:&error];\n    \n    glBindTexture(GL_TEXTURE_2D, self.spritesTexture.name);\n    \n    glActiveTexture(GL_TEXTURE1);\n  \n    [self createNoiseTexture];\n    \n    GLKVector3 backgroundColor = [RVColorProvider vectorForBackgroundColor];\n    glClearColor(backgroundColor.r, backgroundColor.g, backgroundColor.b, 1.0);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glLineWidth([UIScreen mainScreen].scale);\n    \n    glUseProgram(self.pointShader.program);\n    glUniform1i(self.pointShader.texSamplerUniform, 0);\n    \n    GLKVector2 trig[Spans];\n    for (int i = 0; i < Spans; i++) {\n        trig[i].x = cosf(2.0f * M_PI * i/Spans);\n        trig[i].y = sinf(2.0f * M_PI * i/Spans);\n    }\n\n    \n    glUseProgram(self.modelShader.program);\n    glUniform1i(self.modelShader.texSamplerUniform, 1);\n    glUniform2fv(self.modelShader.trigonometryUniform, Spans, (GLfloat*)&trig);\n    \n\n}\n\n- (void)createNoiseTexture\n{\n    static const GLint MaxMipMapLevel = 4;\n    \n    glGenTextures(1, &_noiseTextureName);\n    glBindTexture(GL_TEXTURE_2D, _noiseTextureName);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL_APPLE, MaxMipMapLevel - 1);\n\n    \n    UIImage *image = [UIImage imageNamed:@\"noise\"];\n    \n    CGImageRef imageRef = [image CGImage];\n    \n    size_t width = CGImageGetWidth(imageRef);\n    size_t height = CGImageGetHeight(imageRef);\n    \n    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();\n    NSUInteger bytesPerPixel = 4;\n    NSUInteger bitsPerComponent = 8;\n    \n    \n    for (int level = 0; level < MaxMipMapLevel; level++) {\n        NSUInteger bytesPerRow = bytesPerPixel * width;\n        \n        CGImageRef partImage = CGImageCreateWithImageInRect(imageRef, CGRectMake(0, 0, width, height));\n        \n        unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(*rawData));\n        \n        CGContextRef context = CGBitmapContextCreate(rawData, width, height,\n                                                     bitsPerComponent, bytesPerRow, colorSpace,\n                                                     kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);\n        CGContextSetInterpolationQuality(context, kCGInterpolationNone); // don't blur pixels\n        \n        CGContextDrawImage(context, CGRectMake(0, 0, width, height), partImage);\n        CGContextRelease(context);\n\n        glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rawData);\n        \n        free(rawData);\n        CGImageRelease(partImage);\n        \n        width /= 2;\n        height /= 2;\n    }\n    \n    CGColorSpaceRelease(colorSpace);\n}\n\n\n#pragma mark - Rendering\n\n- (void)render\n{\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n    \n    // left side\n    \n    glViewport(_meshViewport.origin.x, _meshViewport.origin.y, _meshViewport.size.width, _meshViewport.size.height);\n    \n    glEnable(GL_DEPTH_TEST);\n    \n    [self renderSpansFlipped:NO];\n    \n    glDepthMask(GL_FALSE);\n    glEnable(GL_BLEND);\n    [self renderAxis];\n    glDisable(GL_BLEND);\n    \n    // right side\n    \n    glDisable(GL_DEPTH_TEST);\n    glViewport(_drawingViewport.origin.x, _drawingViewport.origin.y, _drawingViewport.size.width, _drawingViewport.size.height);\n    glEnable(GL_BLEND);\n    \n    [self renderGuidelines];\n    \n    glDisable(GL_BLEND);\n     \n    [self renderLines];\n    \n    glEnable(GL_BLEND);\n    \n    [self renderPoints];\n    \n    glDisable(GL_BLEND);\n    glDepthMask(GL_TRUE);\n    \n    glBindVertexArrayOES(0);\n}\n\n- (void)renderModelMesh\n{\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n    \n    glViewport(_meshViewport.origin.x, _meshViewport.origin.y, _meshViewport.size.width, _meshViewport.size.height);\n    glEnable(GL_DEPTH_TEST);\n    \n    [self renderSpansFlipped:YES];\n    \n    glDepthMask(GL_TRUE);\n    glBindVertexArrayOES(0);\n}\n\n\n\n- (void)renderSpansFlipped:(BOOL)flipped\n{\n    glBindVertexArrayOES(self.modelController.VAO);\n    \n    GLKMatrix4 baseViewProjectionMatrix = self.camera.viewProjectionMatrix;\n    GLKMatrix4 baseNormalMatrix = self.camera.viewMatrix;\n    \n    glUseProgram(self.modelShader.program);\n\n    for (RVModelSprite *modelSprite in self.modelController.sprites) {\n        \n        GLKVector3 translation = GLKVector3Add(modelSprite.translationVector, modelSprite.extraTranslationVector);\n        GLKVector3 scale = modelSprite.scaleVector;\n        GLKMatrix4 spriteMatrix = GLKMatrix4Multiply(GLKMatrix4MakeTranslation(translation.x, translation.y, translation.z),\n                                                     GLKMatrix4MakeScale(scale.x, scale.y, scale.z));\n        \n        GLKVector3 modelScale = modelSprite.modelScaleVector;\n        \n        GLKMatrix4 modelScaleMatrix = GLKMatrix4MakeScale(modelScale.x, modelScale.y, modelScale.z);\n        GLKMatrix4 modelRotationMatrix = GLKMatrix4MakeWithQuaternion(modelSprite.quaternion);\n        GLKMatrix4 viewProjectionMatrix = GLKMatrix4Multiply(GLKMatrix4Multiply(baseViewProjectionMatrix, modelScaleMatrix), modelRotationMatrix);\n        GLKMatrix4 normalMatrix = GLKMatrix4Multiply(baseNormalMatrix, modelRotationMatrix);\n        \n        BOOL hasScissors = modelSprite.hasScissors;\n        if (hasScissors) {\n            CGRect scissorsRect = modelSprite.scissorsRect;\n            scissorsRect.origin.x += 1.0f;\n            scissorsRect.origin.y += 1.0f;\n            scissorsRect.origin.x *= _meshViewport.size.width/2.0;\n            scissorsRect.origin.y *= _meshViewport.size.height/2.0;\n            scissorsRect.size.width *= _meshViewport.size.width/2.0;\n            scissorsRect.size.height *= _meshViewport.size.height/2.0;\n            glScissor(scissorsRect.origin.x, scissorsRect.origin.y, scissorsRect.size.width, scissorsRect.size.height);\n            glEnable(GL_SCISSOR_TEST);\n        }\n        \n        \n        GLKMatrix4 viewProjectionModelMatrix = GLKMatrix4Multiply(spriteMatrix, viewProjectionMatrix);\n        GLKMatrix4 normalModelMatrix = normalMatrix;\n        \n        if (flipped) {\n            viewProjectionModelMatrix = GLKMatrix4Multiply(GLKMatrix4MakeScale(1.0, -1.0, 1.0), viewProjectionModelMatrix);\n        }\n        \n        glUniformMatrix3fv(self.modelShader.normalModelMatrixUniform, 1, 0, GLKMatrix4GetMatrix3(normalModelMatrix).m);\n        glUniformMatrix4fv(self.modelShader.viewProjectionModelMatrixUniform, 1, 0, viewProjectionModelMatrix.m);\n        \n        glDrawElementsInstancedEXT(GL_TRIANGLES, modelSprite.indiciesCount, GL_UNSIGNED_SHORT, (GLvoid *)(NSUInteger)modelSprite.indiciesOffset, Spans);\n\n        if (hasScissors) {\n            glDisable(GL_SCISSOR_TEST);\n        }\n    }\n}\n\n- (void)renderAxis\n{\n    if (self.axisController.indiciesCount == 0) {\n        return;\n    }\n    \n    glBindVertexArrayOES(self.axisController.VAO);\n    \n    glUseProgram(self.axisShader.program);\n    GLKMatrix4 baseViewProjectionMatrix = self.camera.viewProjectionMatrix;\n    \n    for (RVModelSprite *modelSprite in self.modelController.sprites) {\n        \n        if (modelSprite.axisAlpha == 0.0f) {\n            continue;\n        }\n        GLKMatrix4 modelRotationMatrix = GLKMatrix4MakeWithQuaternion(modelSprite.quaternion);\n        GLKMatrix4 viewProjectionMatrix = GLKMatrix4Multiply(baseViewProjectionMatrix, modelRotationMatrix);\n        \n        glUniform1f(self.axisShader.alphaUniform, modelSprite.axisAlpha);\n        \n        glUniformMatrix4fv(self.axisShader.viewProjectionModelMatrixUniform, 1, 0, viewProjectionMatrix.m);\n        \n        glDrawElements(GL_LINES, self.axisController.indiciesCount, GL_UNSIGNED_SHORT, 0);\n    }\n    \n    \n}\n\n- (void)renderGuidelines\n{\n    glBindVertexArrayOES(self.guidlineController.VAO);\n    \n    glUseProgram(self.pointShader.program);\n    glUniformMatrix4fv(self.pointShader.viewProjectionMatrixUniform, 1, 0, self.drawingTransformMatrix.m);\n    \n    \n    if (self.guidlineController.indiciesCount > 0) {\n        glDrawElements(GL_TRIANGLES, self.guidlineController.indiciesCount, GL_UNSIGNED_SHORT, 0);\n    }\n}\n\n- (void)renderLines\n{\n    if (self.lineController.indiciesCount == 0) {\n        return;\n    }\n    \n    glBindVertexArrayOES(self.lineController.VAO);\n    \n    glUseProgram(self.lineShader.program);\n    glUniformMatrix4fv(self.lineShader.viewProjectionMatrixUniform, 1, 0, self.drawingTransformMatrix.m);\n    \n    glDrawElements(GL_TRIANGLES, self.lineController.indiciesCount, GL_UNSIGNED_SHORT, 0);\n}\n\n- (void)renderPoints\n{\n    glBindVertexArrayOES(self.pointController.VAO);\n    \n    glUseProgram(self.pointShader.program);\n    glUniformMatrix4fv(self.pointShader.viewProjectionMatrixUniform, 1, 0, self.drawingTransformMatrix.m);\n    \n    \n    if (self.pointController.indiciesCount > 0) {\n        glDrawElements(GL_TRIANGLES, self.pointController.indiciesCount, GL_UNSIGNED_SHORT, 0);\n    }\n}\n\n\n@end\n"
  },
  {
    "path": "Revolved/Revolved-Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>Revolved Model</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Editor</string>\n\t\t\t<key>LSHandlerRank</key>\n\t\t\t<string>Owner</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>com.bartoszciechanowski.revolved.rvlvd</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIcons</key>\n\t<dict/>\n\t<key>CFBundleIcons~ipad</key>\n\t<dict/>\n\t<key>CFBundleIdentifier</key>\n\t<string>com.bartoszciechanowski.revolved</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.1.1</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.1.1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIPrerenderedIcon</key>\n\t<true/>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t\t<string>opengles-2</string>\n\t</array>\n\t<key>UIStatusBarHidden</key>\n\t<true/>\n\t<key>UIStatusBarHidden~ipad</key>\n\t<true/>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UTExportedTypeDeclarations</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>UTTypeConformsTo</key>\n\t\t\t<array>\n\t\t\t\t<string>public.data</string>\n\t\t\t</array>\n\t\t\t<key>UTTypeDescription</key>\n\t\t\t<string>Revolved Model</string>\n\t\t\t<key>UTTypeIdentifier</key>\n\t\t\t<string>com.bartoszciechanowski.revolved.rvlvd</string>\n\t\t\t<key>UTTypeTagSpecification</key>\n\t\t\t<dict>\n\t\t\t\t<key>public.filename-extension</key>\n\t\t\t\t<string>rvlvd</string>\n\t\t\t\t<key>public.mime-type</key>\n\t\t\t\t<string>application/revolved</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Revolved/Revolved-Prefix.pch",
    "content": "//\n// Prefix header for all source files of the 'Revolved' target in the 'Revolved' project\n//\n\n#import <Availability.h>\n\n#ifndef __IPHONE_4_0\n#warning \"This project uses features only available in iOS SDK 4.0 and later.\"\n#endif\n\n#ifdef __OBJC__\n    #import <UIKit/UIKit.h>\n    #import <Foundation/Foundation.h>\n    #import <GLKit/GLKit.h>\n    #import <OpenGLES/ES2/gl.h>\n    #import <OpenGLES/ES2/glext.h>\n    #import \"UIColor+RevolvedColors.h\"\n#endif\n"
  },
  {
    "path": "Revolved/SSZipArchive.h",
    "content": "//\n//  SSZipArchive.h\n//  SSZipArchive\n//\n//  Created by Sam Soffes on 7/21/10.\n//  Copyright (c) Sam Soffes 2010-2011. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#include \"minizip/unzip.h\"\n\n@protocol SSZipArchiveDelegate;\n\n@interface SSZipArchive : NSObject\n\n// Unzip\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination;\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error;\n\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id<SSZipArchiveDelegate>)delegate;\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id<SSZipArchiveDelegate>)delegate;\n\n// Zip\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)filenames;\n\n- (id)initWithPath:(NSString *)path;\n- (BOOL)open;\n- (BOOL)writeFile:(NSString *)path;\n- (BOOL)writeData:(NSData *)data filename:(NSString *)filename;\n- (BOOL)close;\n\n@end\n\n\n@protocol SSZipArchiveDelegate <NSObject>\n\n@optional\n\n- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo;\n- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath;\n\n- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;\n- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;\n\n@end\n"
  },
  {
    "path": "Revolved/SSZipArchive.m",
    "content": "//\n//  SSZipArchive.m\n//  SSZipArchive\n//\n//  Created by Sam Soffes on 7/21/10.\n//  Copyright (c) Sam Soffes 2010-2011. All rights reserved.\n//\n\n#import \"SSZipArchive.h\"\n#include \"minizip/zip.h\"\n#import \"zlib.h\"\n#import \"zconf.h\"\n\n#include <sys/stat.h>\n\n#define CHUNK 16384\n\n@interface SSZipArchive ()\n+ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime;\n@end\n\n\n@implementation SSZipArchive {\n\tNSString *_path;\n\tNSString *_filename;\n    zipFile _zip;\n}\n\n\n#pragma mark - Unzipping\n\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination {\n\treturn [self unzipFileAtPath:path toDestination:destination delegate:nil];\n}\n\n\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error {\n\treturn [self unzipFileAtPath:path toDestination:destination overwrite:overwrite password:password error:error delegate:nil];\n}\n\n\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(id<SSZipArchiveDelegate>)delegate {\n\treturn [self unzipFileAtPath:path toDestination:destination overwrite:YES password:nil error:nil delegate:delegate];\n}\n\n\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(NSString *)password error:(NSError **)error delegate:(id<SSZipArchiveDelegate>)delegate {\n\t// Begin opening\n\tzipFile zip = unzOpen((const char*)[path UTF8String]);\t\n\tif (zip == NULL) {\n\t\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:@\"failed to open zip file\" forKey:NSLocalizedDescriptionKey];\n\t\tif (error) {\n\t\t\t*error = [NSError errorWithDomain:@\"SSZipArchiveErrorDomain\" code:-1 userInfo:userInfo];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tunz_global_info  globalInfo = {0ul, 0ul};\n\tunzGetGlobalInfo(zip, &globalInfo);\n\t\n\t// Begin unzipping\n\tif (unzGoToFirstFile(zip) != UNZ_OK) {\n\t\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:@\"failed to open first file in zip file\" forKey:NSLocalizedDescriptionKey];\n\t\tif (error) {\n\t\t\t*error = [NSError errorWithDomain:@\"SSZipArchiveErrorDomain\" code:-2 userInfo:userInfo];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tBOOL success = YES;\n\tint ret = 0;\n\tunsigned char buffer[4096] = {0};\n\tNSFileManager *fileManager = [NSFileManager defaultManager];\n\tNSMutableSet *directoriesModificationDates = [[NSMutableSet alloc] init];\n\t\n\t// Message delegate\n\tif ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) {\n\t\t[delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo];\n\t}\n\t\n\tNSInteger currentFileNumber = 0;\n\tdo {\n\t\tif ([password length] == 0) {\n\t\t\tret = unzOpenCurrentFile(zip);\n\t\t} else {\n\t\t\tret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSASCIIStringEncoding]);\n\t\t}\n\t\t\n\t\tif (ret != UNZ_OK) {\n\t\t\tsuccess = NO;\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// Reading data and write to file\n\t\tunz_file_info fileInfo;\n\t\tmemset(&fileInfo, 0, sizeof(unz_file_info));\n\t\t\n\t\tret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);\n\t\tif (ret != UNZ_OK) {\n\t\t\tsuccess = NO;\n\t\t\tunzCloseCurrentFile(zip);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// Message delegate\n\t\tif ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {\n\t\t\t[delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry\n\t\t\t\t\t\t\t\t\t\t archivePath:path fileInfo:fileInfo];\n\t\t}\n        \n\t\tchar *filename = (char *)malloc(fileInfo.size_filename + 1);\n\t\tunzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);\n\t\tfilename[fileInfo.size_filename] = '\\0';\n        \n        //\n        // NOTE\n        // I used the ZIP spec from here:\n        // http://www.pkware.com/documents/casestudies/APPNOTE.TXT\n        //\n        // ...to deduce this method of detecting whether the file in the ZIP is a symbolic link.\n        // If it is, it is listed as a directory but has a data size greater than zero (real \n        // directories have it equal to 0) and the included, uncompressed data is the symbolic link path.\n        //\n        // ZIP files did not originally include support for symbolic links so the specification\n        // doesn't include anything in them that isn't part of a unix extension that isn't being used\n        // by the archivers we're testing. Most of this is figured out through trial and error and\n        // reading ZIP headers in hex editors. This seems to do the trick though.\n        //\n        \n        const uLong ZipCompressionMethodStore = 0;\n        \n        BOOL fileIsSymbolicLink = NO;\n        \n        if((fileInfo.compression_method == ZipCompressionMethodStore) && // Is it compressed?\n           (S_ISDIR(fileInfo.external_fa)) && // Is it marked as a directory\n           (fileInfo.compressed_size > 0)) // Is there any data?\n        {\n            fileIsSymbolicLink = YES;\n        }\n        \n\t\t// Check if it contains directory\n\t\tNSString *strPath = [NSString stringWithCString:filename encoding:NSUTF8StringEncoding];\n\t\tBOOL isDirectory = NO;\n\t\tif (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\\\') {\n\t\t\tisDirectory = YES;\n\t\t}\n\t\tfree(filename);\n\t\t\n\t\t// Contains a path\n\t\tif ([strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@\"/\\\\\"]].location != NSNotFound) {\n\t\t\tstrPath = [strPath stringByReplacingOccurrencesOfString:@\"\\\\\" withString:@\"/\"];\n\t\t}\n\t\t\n\t\tNSString *fullPath = [destination stringByAppendingPathComponent:strPath];\n\t\tNSError *err = nil;\n        NSDate *modDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate];\n        NSDictionary *directoryAttr = [NSDictionary dictionaryWithObjectsAndKeys:modDate, NSFileCreationDate, modDate, NSFileModificationDate, nil];\n\t\t\n\t\tif (isDirectory) {\n\t\t\t[fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:directoryAttr  error:&err];\n\t\t} else {\n\t\t\t[fileManager createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:directoryAttr error:&err];\n\t\t}\n        if (nil != err) {\n            NSLog(@\"[SSZipArchive] Error: %@\", err.localizedDescription);\n        }\n\n        if(!fileIsSymbolicLink)\n            [directoriesModificationDates addObject: [NSDictionary dictionaryWithObjectsAndKeys:fullPath, @\"path\", modDate, @\"modDate\", nil]];\n\n        if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) {\n\t\t\tunzCloseCurrentFile(zip);\n\t\t\tret = unzGoToNextFile(zip);\n\t\t\tcontinue;\n\t\t}\n        \n\t\tif(!fileIsSymbolicLink)\n        {\n            FILE *fp = fopen((const char*)[fullPath UTF8String], \"wb\");\n            while (fp) {\n                int readBytes = unzReadCurrentFile(zip, buffer, 4096);\n\n                if (readBytes > 0) {\n                    fwrite(buffer, readBytes, 1, fp );\n                } else {\n                    break;\n                }\n            }\n            \n            if (fp) {\n                fclose(fp);\n                \n                // Set the original datetime property\n                if (fileInfo.dosDate != 0) {\n                    NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.dosDate];\n                    NSDictionary *attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate];\n                    \n                    if (attr) {\n                        if ([fileManager setAttributes:attr ofItemAtPath:fullPath error:nil] == NO) {\n                            // Can't set attributes \n                            NSLog(@\"[SSZipArchive] Failed to set attributes\");\n                        }\n                    }\n                }\n            }\n        }\n        else\n        {\n            // Get the path for the symbolic link\n            \n            NSURL* symlinkURL = [NSURL fileURLWithPath:fullPath];\n            NSMutableString* destinationPath = [NSMutableString string];\n            \n            int bytesRead = 0;\n            while((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0)\n            {\n                buffer[bytesRead] = 0;\n                [destinationPath appendString:[NSString stringWithUTF8String:(const char*)buffer]];\n            }\n            \n            //NSLog(@\"Symlinking to: %@\", destinationPath);\n            \n            NSURL* destinationURL = [NSURL fileURLWithPath:destinationPath];\n            \n            // Create the symbolic link\n            NSError* symlinkError = nil;\n            [fileManager createSymbolicLinkAtURL:symlinkURL withDestinationURL:destinationURL error:&symlinkError];\n            \n            if(symlinkError != nil)\n            {\n                NSLog(@\"Failed to create symbolic link at \\\"%@\\\" to \\\"%@\\\". Error: %@\", symlinkURL.absoluteString, destinationURL.absoluteString, symlinkError.localizedDescription);\n            }\n        }\n\t\t\n\t\tunzCloseCurrentFile( zip );\n\t\tret = unzGoToNextFile( zip );\n\t\t\n\t\t// Message delegate\n\t\tif ([delegate respondsToSelector:@selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {\n\t\t\t[delegate zipArchiveDidUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry\n\t\t\t\t\t\t\t\t\t\t archivePath:path fileInfo:fileInfo];\n\t\t}\n\t\t\n\t\tcurrentFileNumber++;\n\t} while(ret == UNZ_OK && UNZ_OK != UNZ_END_OF_LIST_OF_FILE);\n\t\n\t// Close\n\tunzClose(zip);\n\t\n\t// The process of decompressing the .zip archive causes the modification times on the folders\n    // to be set to the present time. So, when we are done, they need to be explicitly set.\n    // set the modification date on all of the directories.\n    NSError * err = nil;\n    for (NSDictionary * d in directoriesModificationDates) {\n        if (![[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[d objectForKey:@\"modDate\"], NSFileModificationDate, nil] ofItemAtPath:[d objectForKey:@\"path\"] error:&err]) {\n            NSLog(@\"[SSZipArchive] Set attributes failed for directory: %@.\", [d objectForKey:@\"path\"]);\n        }\n        if (err) {\n            NSLog(@\"[SSZipArchive] Error setting directory file modification date attribute: %@\",err.localizedDescription);\n        }\n    }\n\t\n#if !__has_feature(objc_arc)\n\t[directoriesModificationDates release];\n#endif\n\t\n\t// Message delegate\n\tif (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) {\n\t\t[delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination];\n\t}\n\t\n\treturn success;\n}\n\n\n#pragma mark - Zipping\n\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray *)paths {\n\tBOOL success = NO;\n\tSSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];\n\tif ([zipArchive open]) {\n\t\tfor (NSString *path in paths) {\n\t\t\t[zipArchive writeFile:path];\n\t\t}\n\t\tsuccess = [zipArchive close];        \n\t}\n\t\n#if !__has_feature(objc_arc)\n\t[zipArchive release];\n#endif\n\n\treturn success;\n}\n\n\n- (id)initWithPath:(NSString *)path {\n\tif ((self = [super init])) {\n\t\t_path = [path copy];\n\t}\n\treturn self;\n}\n\n\n#if !__has_feature(objc_arc)\n- (void)dealloc {\n    [_path release];\n\t[super dealloc];\n}\n#endif\n\n\n- (BOOL)open {    \n\tNSAssert((_zip == NULL), @\"Attempting open an archive which is already open\");\n\t_zip = zipOpen([_path UTF8String], APPEND_STATUS_CREATE);\n\treturn (NULL != _zip);\n}\n\n\n- (void)zipInfo:(zip_fileinfo*)zipInfo setDate:(NSDate*)date {\n    NSCalendar *currentCalendar = [NSCalendar currentCalendar];\n    uint flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;\n    NSDateComponents *components = [currentCalendar components:flags fromDate:date];\n    zipInfo->tmz_date.tm_sec = (unsigned int)components.second;\n    zipInfo->tmz_date.tm_min = (unsigned int)components.minute;\n    zipInfo->tmz_date.tm_hour = (unsigned int)components.hour;\n    zipInfo->tmz_date.tm_mday = (unsigned int)components.day;\n    zipInfo->tmz_date.tm_mon = (unsigned int)components.month - 1;\n    zipInfo->tmz_date.tm_year = (unsigned int)components.year;\n}\n\n\n- (BOOL)writeFile:(NSString *)path {\n\tNSAssert((_zip != NULL), @\"Attempting to write to an archive which was never opened\");\n\n\tFILE *input = fopen([path UTF8String], \"r\");\n\tif (NULL == input) {\n\t\treturn NO;\n\t}\n\n\tzipOpenNewFileInZip(_zip, [[path lastPathComponent] UTF8String], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED,\n\t\t\t\t\t\tZ_DEFAULT_COMPRESSION);\n\n\tvoid *buffer = malloc(CHUNK);\n\tunsigned int len = 0;\n\twhile (!feof(input)) {\n\t\tlen = (unsigned int) fread(buffer, 1, CHUNK, input);\n\t\tzipWriteInFileInZip(_zip, buffer, len);\n\t}\n\n\tzipCloseFileInZip(_zip);\n\tfree(buffer);\n\treturn YES;\n}\n\n\n- (BOOL)writeData:(NSData *)data filename:(NSString *)filename {\n    if (!_zip) {\n\t\treturn NO;\n    }\n    if (!data) {\n\t\treturn NO;\n    }\n    zip_fileinfo zipInfo = {{0,0,0,0,0,0},0,0,0};\n    [self zipInfo:&zipInfo setDate:[NSDate date]];\n\n\tzipOpenNewFileInZip(_zip, [filename UTF8String], &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);\n\n    zipWriteInFileInZip(_zip, data.bytes, (unsigned int)data.length);\n\n\tzipCloseFileInZip(_zip);\n\treturn YES;\n}\n\n\n- (BOOL)close {    \n\tNSAssert((_zip != NULL), @\"[SSZipArchive] Attempting to close an archive which was never opened\");\n\tzipClose(_zip, NULL);\n\treturn YES;\n}\n\n\n#pragma mark - Private\n\n// Format from http://newsgroups.derkeiler.com/Archive/Comp/comp.os.msdos.programmer/2009-04/msg00060.html\n// Two consecutive words, or a longword, YYYYYYYMMMMDDDDD hhhhhmmmmmmsssss\n// YYYYYYY is years from 1980 = 0\n// sssss is (seconds/2).\n//\n// 3658 = 0011 0110 0101 1000 = 0011011 0010 11000 = 27 2 24 = 2007-02-24\n// 7423 = 0111 0100 0010 0011 - 01110 100001 00011 = 14 33 2 = 14:33:06\n+ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime {\n\tstatic const UInt32 kYearMask = 0xFE000000;\n\tstatic const UInt32 kMonthMask = 0x1E00000;\n\tstatic const UInt32 kDayMask = 0x1F0000;\n\tstatic const UInt32 kHourMask = 0xF800;\n\tstatic const UInt32 kMinuteMask = 0x7E0;\n\tstatic const UInt32 kSecondMask = 0x1F;\n\t\n\tNSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];\n    NSDateComponents *components = [[NSDateComponents alloc] init];\n\n    NSAssert(0xFFFFFFFF == (kYearMask | kMonthMask | kDayMask | kHourMask | kMinuteMask | kSecondMask), @\"[SSZipArchive] MSDOS date masks don't add up\");\n\t    \n    [components setYear:1980 + ((msdosDateTime & kYearMask) >> 25)];\n    [components setMonth:(msdosDateTime & kMonthMask) >> 21];\n    [components setDay:(msdosDateTime & kDayMask) >> 16];\n    [components setHour:(msdosDateTime & kHourMask) >> 11];\n    [components setMinute:(msdosDateTime & kMinuteMask) >> 5];\n    [components setSecond:(msdosDateTime & kSecondMask) * 2];\n    \n    NSDate *date = [NSDate dateWithTimeInterval:0 sinceDate:[gregorian dateFromComponents:components]];\n\t\n#if !__has_feature(objc_arc)\n\t[gregorian release];\n\t[components release];\n#endif\n\t\n\treturn date;\n}\n\n@end\n"
  },
  {
    "path": "Revolved/SegmentEnd.h",
    "content": "//\n//  SegmentEnd.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 10.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#ifndef Revolved_SegmentEnd_h\n#define Revolved_SegmentEnd_h\n\ntypedef NS_ENUM(NSInteger, SegmentEnd) {\n    SegmentEndFirst,\n    SegmentEndSecond\n};\n\n#endif\n"
  },
  {
    "path": "Revolved/UIColor+RevolvedColors.h",
    "content": "//\n//  UIColor+RevolvedColors.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface UIColor (RevolvedColors)\n\n+ (UIColor *)rv_backgroundColor;\n+ (UIColor *)rv_tintColor;\n+ (UIColor *)rv_dimColor;\n\n@end\n"
  },
  {
    "path": "Revolved/UIColor+RevolvedColors.m",
    "content": "//\n//  UIColor+RevolvedColors.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"UIColor+RevolvedColors.h\"\n\n@implementation UIColor (RevolvedColors)\n\n+ (UIColor *)rv_backgroundColor\n{\n    return [UIColor colorWithWhite:0.93 alpha:1.0];\n}\n\n+ (UIColor *)rv_tintColor\n{\n    return [UIColor colorWithWhite:0.72 alpha:1.0];\n}\n\n+ (UIColor *)rv_dimColor\n{\n    return [UIColor colorWithWhite:0.12 alpha:0.85];\n}\n\n@end\n"
  },
  {
    "path": "Revolved/UIView+RotationAnimation.h",
    "content": "//\n//  UIView+RotationAnimation.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 28.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@class RVAnimation;\n@interface UIView (RotationAnimation)\n\n- (void)rv_setRotation:(float)rotation;\n- (float)rv_Rotation;\n\n- (void)rv_addAnimation:(RVAnimation *)animation forKey:(NSString *)key;\n\n@end\n"
  },
  {
    "path": "Revolved/UIView+RotationAnimation.m",
    "content": "//\n//  UIView+RotationAnimation.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 28.09.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import \"UIView+RotationAnimation.h\"\n#import \"RVAnimator.h\"\n\n@implementation UIView (RotationAnimation)\n\n- (void)rv_setRotation:(float)rotation;\n{\n    self.transform = CGAffineTransformMakeRotation(rotation);\n}\n\n- (float)rv_Rotation\n{\n    float value = atan2f(self.transform.b, self.transform.a);\n    \n    return value;\n}\n\n- (void)rv_addAnimation:(RVAnimation *)animation forKey:(NSString *)key\n{\n    [[RVAnimator sharedAnimator] addAnimation:animation forKey:key toTarget:self];\n}\n\n\n\n\n@end\n"
  },
  {
    "path": "Revolved/Vertex.h",
    "content": "//\n//  Vertex.h\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#ifndef Revolved_Vertex_h\n#define Revolved_Vertex_h\n\ntypedef struct Vertex {\n    GLKVector3 p;\n    GLKVector3 n;\n    GLKVector3 color;\n    GLKVector2 uv;\n} Vertex;\n\n#endif\n"
  },
  {
    "path": "Revolved/en.lproj/InfoPlist.strings",
    "content": "/* Localized versions of Info.plist keys */\n\n"
  },
  {
    "path": "Revolved/mail.txt",
    "content": "Check out this 3D model I've made in Revolved.\n\nDon't have the app on your iPad? Get it at:\nhttp://bit.ly/Rvlvd"
  },
  {
    "path": "Revolved/main.m",
    "content": "//\n//  main.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 03.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n#import \"AppDelegate.h\"\n\nint main(int argc, char *argv[])\n{\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n    }\n}\n"
  },
  {
    "path": "Revolved/minizip/crypt.h",
    "content": "/* crypt.h -- base code for crypt/uncrypt ZIPfile\n\n\n   Version 1.01e, February 12th, 2005\n\n   Copyright (C) 1998-2005 Gilles Vollant\n\n   This code is a modified version of crypting code in Infozip distribution\n\n   The encryption/decryption parts of this source code (as opposed to the\n   non-echoing password parts) were originally written in Europe.  The\n   whole source package can be freely distributed, including from the USA.\n   (Prior to January 2000, re-export from the US was a violation of US law.)\n\n   This encryption code is a direct transcription of the algorithm from\n   Roger Schlafly, described by Phil Katz in the file appnote.txt.  This\n   file (appnote.txt) is distributed with the PKZIP program (even in the\n   version without encryption capabilities).\n\n   If you don't need crypting in your application, just define symbols\n   NOCRYPT and NOUNCRYPT.\n\n   This code support the \"Traditional PKWARE Encryption\".\n\n   The new AES encryption added on Zip format by Winzip (see the page\n   http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong\n   Encryption is not supported.\n*/\n\n#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))\n\n/***********************************************************************\n * Return the next byte in the pseudo-random sequence\n */\nstatic int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)\n{\n    unsigned temp;  /* POTENTIAL BUG:  temp*(temp^1) may overflow in an\n                     * unpredictable manner on 16-bit systems; not a problem\n                     * with any known compiler so far, though */\n\n    temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;\n    return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);\n}\n\n/***********************************************************************\n * Update the encryption keys with the next byte of plain text\n */\nstatic int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)\n{\n    (*(pkeys+0)) = CRC32((*(pkeys+0)), c);\n    (*(pkeys+1)) += (*(pkeys+0)) & 0xff;\n    (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;\n    {\n      register int keyshift = (int)((*(pkeys+1)) >> 24);\n      (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);\n    }\n    return c;\n}\n\n\n/***********************************************************************\n * Initialize the encryption keys and the random header according to\n * the given password.\n */\nstatic void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)\n{\n    *(pkeys+0) = 305419896L;\n    *(pkeys+1) = 591751049L;\n    *(pkeys+2) = 878082192L;\n    while (*passwd != '\\0') {\n        update_keys(pkeys,pcrc_32_tab,(int)*passwd);\n        passwd++;\n    }\n}\n\n#define zdecode(pkeys,pcrc_32_tab,c) \\\n    (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))\n\n#define zencode(pkeys,pcrc_32_tab,c,t) \\\n    (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))\n\n#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED\n\n#define RAND_HEAD_LEN  12\n   /* \"last resort\" source for second part of crypt seed pattern */\n#  ifndef ZCR_SEED2\n#    define ZCR_SEED2 3141592654UL     /* use PI as default pattern */\n#  endif\n\nstatic int crypthead(const char* passwd,      /* password string */\n                     unsigned char* buf,      /* where to write header */\n                     int bufSize,\n                     unsigned long* pkeys,\n                     const unsigned long* pcrc_32_tab,\n                     unsigned long crcForCrypting)\n{\n    int n;                       /* index in random header */\n    int t;                       /* temporary */\n    int c;                       /* random byte */\n    unsigned char header[RAND_HEAD_LEN-2]; /* random header */\n    static unsigned calls = 0;   /* ensure different random header each time */\n\n    if (bufSize<RAND_HEAD_LEN)\n      return 0;\n\n    /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the\n     * output of rand() to get less predictability, since rand() is\n     * often poorly implemented.\n     */\n    if (++calls == 1)\n    {\n        srand((unsigned)(time(NULL) ^ ZCR_SEED2));\n    }\n    init_keys(passwd, pkeys, pcrc_32_tab);\n    for (n = 0; n < RAND_HEAD_LEN-2; n++)\n    {\n        c = (rand() >> 7) & 0xff;\n        header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);\n    }\n    /* Encrypt random header (last two bytes is high word of crc) */\n    init_keys(passwd, pkeys, pcrc_32_tab);\n    for (n = 0; n < RAND_HEAD_LEN-2; n++)\n    {\n        buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);\n    }\n    buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);\n    buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);\n    return n;\n}\n\n#endif\n"
  },
  {
    "path": "Revolved/minizip/ioapi.c",
    "content": "/* ioapi.h -- IO base function header for compress/uncompress .zip\n   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Modifications for Zip64 support\n         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )\n\n         For more info read MiniZip_info.txt\n\n*/\n\n#if (defined(_WIN32))\n        #define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#include \"ioapi.h\"\n\nvoidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)\n{\n    if (pfilefunc->zfile_func64.zopen64_file != NULL)\n        return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);\n    else\n    {\n        return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);\n    }\n}\n\nlong call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)\n{\n    if (pfilefunc->zfile_func64.zseek64_file != NULL)\n        return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);\n    else\n    {\n        uLong offsetTruncated = (uLong)offset;\n        if (offsetTruncated != offset)\n            return -1;\n        else\n            return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);\n    }\n}\n\nZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)\n{\n    if (pfilefunc->zfile_func64.zseek64_file != NULL)\n        return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);\n    else\n    {\n        uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);\n        if ((tell_uLong) == ((uLong)-1))\n            return (ZPOS64_T)-1;\n        else\n            return tell_uLong;\n    }\n}\n\nvoid fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)\n{\n    p_filefunc64_32->zfile_func64.zopen64_file = NULL;\n    p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;\n    p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;\n    p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;\n    p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;\n    p_filefunc64_32->zfile_func64.ztell64_file = NULL;\n    p_filefunc64_32->zfile_func64.zseek64_file = NULL;\n    p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;\n\n#ifndef __clang_analyzer__\n    p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;\n#endif\n\t\n    p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;\n    p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;\n    p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;\n}\n\n\n\nstatic voidpf  ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));\nstatic uLong   ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));\nstatic uLong   ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));\nstatic ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));\nstatic long    ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));\nstatic int     ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));\nstatic int     ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));\n\nstatic voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)\n{\n    FILE* file = NULL;\n    const char* mode_fopen = NULL;\n    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)\n        mode_fopen = \"rb\";\n    else\n    if (mode & ZLIB_FILEFUNC_MODE_EXISTING)\n        mode_fopen = \"r+b\";\n    else\n    if (mode & ZLIB_FILEFUNC_MODE_CREATE)\n        mode_fopen = \"wb\";\n\n    if ((filename!=NULL) && (mode_fopen != NULL))\n        file = fopen(filename, mode_fopen);\n    return file;\n}\n\nstatic voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)\n{\n    FILE* file = NULL;\n    const char* mode_fopen = NULL;\n    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)\n        mode_fopen = \"rb\";\n    else\n    if (mode & ZLIB_FILEFUNC_MODE_EXISTING)\n        mode_fopen = \"r+b\";\n    else\n    if (mode & ZLIB_FILEFUNC_MODE_CREATE)\n        mode_fopen = \"wb\";\n\n    if ((filename!=NULL) && (mode_fopen != NULL))\n        file = fopen64((const char*)filename, mode_fopen);\n    return file;\n}\n\n\nstatic uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)\n{\n    uLong ret;\n    ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);\n    return ret;\n}\n\nstatic uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)\n{\n    uLong ret;\n    ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);\n    return ret;\n}\n\nstatic long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)\n{\n    long ret;\n    ret = ftell((FILE *)stream);\n    return ret;\n}\n\n\nstatic ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)\n{\n    ZPOS64_T ret;\n    ret = ftello64((FILE *)stream);\n    return ret;\n}\n\nstatic long ZCALLBACK fseek_file_func (voidpf  opaque, voidpf stream, uLong offset, int origin)\n{\n    int fseek_origin=0;\n    long ret;\n    switch (origin)\n    {\n    case ZLIB_FILEFUNC_SEEK_CUR :\n        fseek_origin = SEEK_CUR;\n        break;\n    case ZLIB_FILEFUNC_SEEK_END :\n        fseek_origin = SEEK_END;\n        break;\n    case ZLIB_FILEFUNC_SEEK_SET :\n        fseek_origin = SEEK_SET;\n        break;\n    default: return -1;\n    }\n    ret = 0;\n    if (fseek((FILE *)stream, offset, fseek_origin) != 0)\n        ret = -1;\n    return ret;\n}\n\nstatic long ZCALLBACK fseek64_file_func (voidpf  opaque, voidpf stream, ZPOS64_T offset, int origin)\n{\n    int fseek_origin=0;\n    long ret;\n    switch (origin)\n    {\n    case ZLIB_FILEFUNC_SEEK_CUR :\n        fseek_origin = SEEK_CUR;\n        break;\n    case ZLIB_FILEFUNC_SEEK_END :\n        fseek_origin = SEEK_END;\n        break;\n    case ZLIB_FILEFUNC_SEEK_SET :\n        fseek_origin = SEEK_SET;\n        break;\n    default: return -1;\n    }\n    ret = 0;\n\n    if(fseeko64((FILE *)stream, offset, fseek_origin) != 0)\n                        ret = -1;\n\n    return ret;\n}\n\n\nstatic int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)\n{\n    int ret;\n    ret = fclose((FILE *)stream);\n    return ret;\n}\n\nstatic int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)\n{\n    int ret;\n    ret = ferror((FILE *)stream);\n    return ret;\n}\n\nvoid fill_fopen_filefunc (pzlib_filefunc_def)\n  zlib_filefunc_def* pzlib_filefunc_def;\n{\n    pzlib_filefunc_def->zopen_file = fopen_file_func;\n    pzlib_filefunc_def->zread_file = fread_file_func;\n    pzlib_filefunc_def->zwrite_file = fwrite_file_func;\n    pzlib_filefunc_def->ztell_file = ftell_file_func;\n    pzlib_filefunc_def->zseek_file = fseek_file_func;\n    pzlib_filefunc_def->zclose_file = fclose_file_func;\n    pzlib_filefunc_def->zerror_file = ferror_file_func;\n    pzlib_filefunc_def->opaque = NULL;\n}\n\nvoid fill_fopen64_filefunc (zlib_filefunc64_def*  pzlib_filefunc_def)\n{\n    pzlib_filefunc_def->zopen64_file = fopen64_file_func;\n    pzlib_filefunc_def->zread_file = fread_file_func;\n    pzlib_filefunc_def->zwrite_file = fwrite_file_func;\n    pzlib_filefunc_def->ztell64_file = ftell64_file_func;\n    pzlib_filefunc_def->zseek64_file = fseek64_file_func;\n    pzlib_filefunc_def->zclose_file = fclose_file_func;\n    pzlib_filefunc_def->zerror_file = ferror_file_func;\n    pzlib_filefunc_def->opaque = NULL;\n}\n"
  },
  {
    "path": "Revolved/minizip/ioapi.h",
    "content": "/* ioapi.h -- IO base function header for compress/uncompress .zip\n   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Modifications for Zip64 support\n         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )\n\n         For more info read MiniZip_info.txt\n\n         Changes\n\n    Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)\n    Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.\n               More if/def section may be needed to support other platforms\n    Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.\n                          (but you should use iowin32.c for windows instead)\n\n*/\n\n#ifndef _ZLIBIOAPI64_H\n#define _ZLIBIOAPI64_H\n\n#if (!defined(_WIN32)) && (!defined(WIN32))\n\n  // Linux needs this to support file operation on files larger then 4+GB\n  // But might need better if/def to select just the platforms that needs them.\n\n        #ifndef __USE_FILE_OFFSET64\n                #define __USE_FILE_OFFSET64\n        #endif\n        #ifndef __USE_LARGEFILE64\n                #define __USE_LARGEFILE64\n        #endif\n        #ifndef _LARGEFILE64_SOURCE\n                #define _LARGEFILE64_SOURCE\n        #endif\n        #ifndef _FILE_OFFSET_BIT\n                #define _FILE_OFFSET_BIT 64\n        #endif\n#endif\n\n#include <stdio.h>\n#include <stdlib.h>\n#include \"zlib.h\"\n\n#define USE_FILE32API\n#if defined(USE_FILE32API)\n#define fopen64 fopen\n#define ftello64 ftell\n#define fseeko64 fseek\n#else\n#ifdef _MSC_VER\n #define fopen64 fopen\n #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))\n  #define ftello64 _ftelli64\n  #define fseeko64 _fseeki64\n #else // old MSC\n  #define ftello64 ftell\n  #define fseeko64 fseek\n #endif\n#endif\n#endif\n\n/*\n#ifndef ZPOS64_T\n  #ifdef _WIN32\n                #define ZPOS64_T fpos_t\n  #else\n    #include <stdint.h>\n    #define ZPOS64_T uint64_t\n  #endif\n#endif\n*/\n\n#ifdef HAVE_MINIZIP64_CONF_H\n#include \"mz64conf.h\"\n#endif\n\n/* a type choosen by DEFINE */\n#ifdef HAVE_64BIT_INT_CUSTOM\ntypedef  64BIT_INT_CUSTOM_TYPE ZPOS64_T;\n#else\n#ifdef HAS_STDINT_H\n#include \"stdint.h\"\ntypedef uint64_t ZPOS64_T;\n#else\n\n\n#if defined(_MSC_VER) || defined(__BORLANDC__)\ntypedef unsigned __int64 ZPOS64_T;\n#else\ntypedef unsigned long long int ZPOS64_T;\n#endif\n#endif\n#endif\n\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n#define ZLIB_FILEFUNC_SEEK_CUR (1)\n#define ZLIB_FILEFUNC_SEEK_END (2)\n#define ZLIB_FILEFUNC_SEEK_SET (0)\n\n#define ZLIB_FILEFUNC_MODE_READ      (1)\n#define ZLIB_FILEFUNC_MODE_WRITE     (2)\n#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)\n\n#define ZLIB_FILEFUNC_MODE_EXISTING (4)\n#define ZLIB_FILEFUNC_MODE_CREATE   (8)\n\n\n#ifndef ZCALLBACK\n #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)\n   #define ZCALLBACK CALLBACK\n #else\n   #define ZCALLBACK\n #endif\n#endif\n\n\n\n\ntypedef voidpf   (ZCALLBACK *open_file_func)      OF((voidpf opaque, const char* filename, int mode));\ntypedef uLong    (ZCALLBACK *read_file_func)      OF((voidpf opaque, voidpf stream, void* buf, uLong size));\ntypedef uLong    (ZCALLBACK *write_file_func)     OF((voidpf opaque, voidpf stream, const void* buf, uLong size));\ntypedef int      (ZCALLBACK *close_file_func)     OF((voidpf opaque, voidpf stream));\ntypedef int      (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));\n\ntypedef long     (ZCALLBACK *tell_file_func)      OF((voidpf opaque, voidpf stream));\ntypedef long     (ZCALLBACK *seek_file_func)      OF((voidpf opaque, voidpf stream, uLong offset, int origin));\n\n\n/* here is the \"old\" 32 bits structure structure */\ntypedef struct zlib_filefunc_def_s\n{\n    open_file_func      zopen_file;\n    read_file_func      zread_file;\n    write_file_func     zwrite_file;\n    tell_file_func      ztell_file;\n    seek_file_func      zseek_file;\n    close_file_func     zclose_file;\n    testerror_file_func zerror_file;\n    voidpf              opaque;\n} zlib_filefunc_def;\n\ntypedef ZPOS64_T (ZCALLBACK *tell64_file_func)    OF((voidpf opaque, voidpf stream));\ntypedef long     (ZCALLBACK *seek64_file_func)    OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));\ntypedef voidpf   (ZCALLBACK *open64_file_func)    OF((voidpf opaque, const void* filename, int mode));\n\ntypedef struct zlib_filefunc64_def_s\n{\n    open64_file_func    zopen64_file;\n    read_file_func      zread_file;\n    write_file_func     zwrite_file;\n    tell64_file_func    ztell64_file;\n    seek64_file_func    zseek64_file;\n    close_file_func     zclose_file;\n    testerror_file_func zerror_file;\n    voidpf              opaque;\n} zlib_filefunc64_def;\n\nvoid fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));\nvoid fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));\n\n/* now internal definition, only for zip.c and unzip.h */\ntypedef struct zlib_filefunc64_32_def_s\n{\n    zlib_filefunc64_def zfile_func64;\n    open_file_func      zopen32_file;\n    tell_file_func      ztell32_file;\n    seek_file_func      zseek32_file;\n} zlib_filefunc64_32_def;\n\n\n#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))\n#define ZWRITE64(filefunc,filestream,buf,size)    ((*((filefunc).zfile_func64.zwrite_file))  ((filefunc).zfile_func64.opaque,filestream,buf,size))\n//#define ZTELL64(filefunc,filestream)            ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))\n//#define ZSEEK64(filefunc,filestream,pos,mode)   ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))\n#define ZCLOSE64(filefunc,filestream)             ((*((filefunc).zfile_func64.zclose_file))  ((filefunc).zfile_func64.opaque,filestream))\n#define ZERROR64(filefunc,filestream)             ((*((filefunc).zfile_func64.zerror_file))  ((filefunc).zfile_func64.opaque,filestream))\n\nvoidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));\nlong    call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));\nZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));\n\nvoid    fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);\n\n#define ZOPEN64(filefunc,filename,mode)         (call_zopen64((&(filefunc)),(filename),(mode)))\n#define ZTELL64(filefunc,filestream)            (call_ztell64((&(filefunc)),(filestream)))\n#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "Revolved/minizip/mztools.c",
    "content": "/*\n  Additional tools for Minizip\n  Code: Xavier Roche '2004\n  License: Same as ZLIB (www.gzip.org)\n*/\n\n/* Code */\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"zlib.h\"\n#include \"unzip.h\"\n#include \"mztools.h\"\n\n#define READ_8(adr)  ((unsigned char)*(adr))\n#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) )\n#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) )\n\n#define WRITE_8(buff, n) do { \\\n  *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \\\n} while(0)\n#define WRITE_16(buff, n) do { \\\n  WRITE_8((unsigned char*)(buff), n); \\\n  WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \\\n} while(0)\n#define WRITE_32(buff, n) do { \\\n  WRITE_16((unsigned char*)(buff), (n) & 0xffff); \\\n  WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \\\n} while(0)\n\nextern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered)\nconst char* file;\nconst char* fileOut;\nconst char* fileOutTmp;\nuLong* nRecovered;\nuLong* bytesRecovered;\n{\n  int err = Z_OK;\n  FILE* fpZip = fopen(file, \"rb\");\n  FILE* fpOut = fopen(fileOut, \"wb\");\n  FILE* fpOutCD = fopen(fileOutTmp, \"wb\");\n  if (fpZip != NULL &&  fpOut != NULL) {\n    int entries = 0;\n    uLong totalBytes = 0;\n    char header[30];\n    char filename[256];\n    char extra[1024];\n    int offset = 0;\n    int offsetCD = 0;\n    while ( fread(header, 1, 30, fpZip) == 30 ) {\n      int currentOffset = offset;\n\n      /* File entry */\n      if (READ_32(header) == 0x04034b50) {\n        unsigned int version = READ_16(header + 4);\n        unsigned int gpflag = READ_16(header + 6);\n        unsigned int method = READ_16(header + 8);\n        unsigned int filetime = READ_16(header + 10);\n        unsigned int filedate = READ_16(header + 12);\n        unsigned int crc = READ_32(header + 14); /* crc */\n        unsigned int cpsize = READ_32(header + 18); /* compressed size */\n        unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */\n        unsigned int fnsize = READ_16(header + 26); /* file name length */\n        unsigned int extsize = READ_16(header + 28); /* extra field length */\n        filename[0] = extra[0] = '\\0';\n        \n        /* Header */\n        if (fwrite(header, 1, 30, fpOut) == 30) {\n          offset += 30;\n        } else {\n          err = Z_ERRNO;\n          break;\n        }\n        \n        /* Filename */\n        if (fnsize > 0) {\n          if (fread(filename, 1, fnsize, fpZip) == fnsize) {\n            if (fwrite(filename, 1, fnsize, fpOut) == fnsize) {\n              offset += fnsize;\n            } else {\n              err = Z_ERRNO;\n              break;\n            }\n          } else {\n            err = Z_ERRNO;\n            break;\n          }\n        } else {\n          err = Z_STREAM_ERROR;\n          break;\n        }\n\n        /* Extra field */\n        if (extsize > 0) {\n          if (fread(extra, 1, extsize, fpZip) == extsize) {\n            if (fwrite(extra, 1, extsize, fpOut) == extsize) {\n              offset += extsize;\n            } else {\n              err = Z_ERRNO;\n              break;\n            }\n          } else {\n            err = Z_ERRNO;\n            break;\n          }\n        }\n        \n        /* Data */\n        {\n          int dataSize = cpsize;\n          if (dataSize == 0) {\n            dataSize = uncpsize;\n          }\n          if (dataSize > 0) {\n            char* data = malloc(dataSize);\n            if (data != NULL) {\n              if ((int)fread(data, 1, dataSize, fpZip) == dataSize) {\n                if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) {\n                  offset += dataSize;\n                  totalBytes += dataSize;\n                } else {\n                  err = Z_ERRNO;\n                }\n              } else {\n                err = Z_ERRNO;\n              }\n              free(data);\n              if (err != Z_OK) {\n                break;\n              }\n            } else {\n              err = Z_MEM_ERROR;\n              break;\n            }\n          }\n        }\n        \n        /* Central directory entry */\n        {\n          char centralDirectoryEntryHeader[46];\n          //char* comment = \"\";\n          //int comsize = (int) strlen(comment);\n          WRITE_32(centralDirectoryEntryHeader, 0x02014b50);\n          WRITE_16(centralDirectoryEntryHeader + 4, version);\n          WRITE_16(centralDirectoryEntryHeader + 6, version);\n          WRITE_16(centralDirectoryEntryHeader + 8, gpflag);\n          WRITE_16(centralDirectoryEntryHeader + 10, method);\n          WRITE_16(centralDirectoryEntryHeader + 12, filetime);\n          WRITE_16(centralDirectoryEntryHeader + 14, filedate);\n          WRITE_32(centralDirectoryEntryHeader + 16, crc);\n          WRITE_32(centralDirectoryEntryHeader + 20, cpsize);\n          WRITE_32(centralDirectoryEntryHeader + 24, uncpsize);\n          WRITE_16(centralDirectoryEntryHeader + 28, fnsize);\n          WRITE_16(centralDirectoryEntryHeader + 30, extsize);\n          WRITE_16(centralDirectoryEntryHeader + 32, 0 /*comsize*/);\n          WRITE_16(centralDirectoryEntryHeader + 34, 0);     /* disk # */\n          WRITE_16(centralDirectoryEntryHeader + 36, 0);     /* int attrb */\n          WRITE_32(centralDirectoryEntryHeader + 38, 0);     /* ext attrb */\n          WRITE_32(centralDirectoryEntryHeader + 42, currentOffset);\n          /* Header */\n          if (fwrite(centralDirectoryEntryHeader, 1, 46, fpOutCD) == 46) {\n            offsetCD += 46;\n            \n            /* Filename */\n            if (fnsize > 0) {\n              if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) {\n                offsetCD += fnsize;\n              } else {\n                err = Z_ERRNO;\n                break;\n              }\n            } else {\n              err = Z_STREAM_ERROR;\n              break;\n            }\n            \n            /* Extra field */\n            if (extsize > 0) {\n              if (fwrite(extra, 1, extsize, fpOutCD) == extsize) {\n                offsetCD += extsize;\n              } else {\n                err = Z_ERRNO;\n                break;\n              }\n            }\n            \n            /* Comment field */\n            /*\n            if (comsize > 0) {\n              if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) {\n                offsetCD += comsize;\n              } else {\n                err = Z_ERRNO;\n                break;\n              }\n            }\n            */\n            \n          } else {\n            err = Z_ERRNO;\n            break;\n          }\n        }\n\n        /* Success */\n        entries++;\n\n      } else {\n        break;\n      }\n    }\n\n    /* Final central directory  */\n    {\n      int entriesZip = entries;\n      char finalCentralDirectoryHeader[22];\n      //char* comment = \"\"; // \"ZIP File recovered by zlib/minizip/mztools\";\n      //int comsize = (int) strlen(comment);\n      if (entriesZip > 0xffff) {\n        entriesZip = 0xffff;\n      }\n      WRITE_32(finalCentralDirectoryHeader, 0x06054b50);\n      WRITE_16(finalCentralDirectoryHeader + 4, 0);    /* disk # */\n      WRITE_16(finalCentralDirectoryHeader + 6, 0);    /* disk # */\n      WRITE_16(finalCentralDirectoryHeader + 8, entriesZip);   /* hack */\n      WRITE_16(finalCentralDirectoryHeader + 10, entriesZip);  /* hack */\n      WRITE_32(finalCentralDirectoryHeader + 12, offsetCD);    /* size of CD */\n      WRITE_32(finalCentralDirectoryHeader + 16, offset);      /* offset to CD */\n      WRITE_16(finalCentralDirectoryHeader + 20, 0 /*comsize*/);     /* comment */\n      \n      /* Header */\n      if (fwrite(finalCentralDirectoryHeader, 1, 22, fpOutCD) == 22) {\n        \n        /* Comment field */\n        /*\n        if (comsize > 0) {\n          if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) {\n            err = Z_ERRNO;\n          }\n        }\n        */\n      } else {\n        err = Z_ERRNO;\n      }\n    }\n\n    /* Final merge (file + central directory) */\n    fclose(fpOutCD);\n    if (err == Z_OK) {\n      fpOutCD = fopen(fileOutTmp, \"rb\");\n      if (fpOutCD != NULL) {\n        int nRead;\n        char buffer[8192];\n        while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) {\n          if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) {\n            err = Z_ERRNO;\n            break;\n          }\n        }\n        fclose(fpOutCD);\n      }\n    }\n    \n    /* Close */\n    fclose(fpZip);\n    fclose(fpOut);\n    \n    /* Wipe temporary file */\n    (void)remove(fileOutTmp);\n    \n    /* Number of recovered entries */\n    if (err == Z_OK) {\n      if (nRecovered != NULL) {\n        *nRecovered = entries;\n      }\n      if (bytesRecovered != NULL) {\n        *bytesRecovered = totalBytes;\n      }\n    }\n  } else {\n    err = Z_STREAM_ERROR;\n  }\n  return err;\n}\n"
  },
  {
    "path": "Revolved/minizip/mztools.h",
    "content": "/*\n  Additional tools for Minizip\n  Code: Xavier Roche '2004\n  License: Same as ZLIB (www.gzip.org)\n*/\n\n#ifndef _zip_tools_H\n#define _zip_tools_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef _ZLIB_H\n#include \"zlib.h\"\n#endif\n\n#include \"unzip.h\"\n\n/* Repair a ZIP file (missing central directory)\n   file: file to recover\n   fileOut: output file after recovery\n   fileOutTmp: temporary file name used for recovery\n*/\nextern int ZEXPORT unzRepair(const char* file,\n                             const char* fileOut,\n                             const char* fileOutTmp,\n                             uLong* nRecovered,\n                             uLong* bytesRecovered);\n\n#endif\n"
  },
  {
    "path": "Revolved/minizip/unzip.c",
    "content": "/* unzip.c -- IO for uncompress .zip files using zlib\n   Version 1.1, February 14h, 2010\n   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Modifications of Unzip for Zip64\n         Copyright (C) 2007-2008 Even Rouault\n\n         Modifications for Zip64 support on both zip and unzip\n         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )\n\n         For more info read MiniZip_info.txt\n\n\n  ------------------------------------------------------------------------------------\n  Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of\n  compatibility with older software. The following is from the original crypt.c.\n  Code woven in by Terry Thorsen 1/2003.\n\n  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.\n\n  See the accompanying file LICENSE, version 2000-Apr-09 or later\n  (the contents of which are also included in zip.h) for terms of use.\n  If, for some reason, all these files are missing, the Info-ZIP license\n  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html\n\n        crypt.c (full version) by Info-ZIP.      Last revised:  [see crypt.h]\n\n  The encryption/decryption parts of this source code (as opposed to the\n  non-echoing password parts) were originally written in Europe.  The\n  whole source package can be freely distributed, including from the USA.\n  (Prior to January 2000, re-export from the US was a violation of US law.)\n\n        This encryption code is a direct transcription of the algorithm from\n  Roger Schlafly, described by Phil Katz in the file appnote.txt.  This\n  file (appnote.txt) is distributed with the PKZIP program (even in the\n  version without encryption capabilities).\n\n        ------------------------------------------------------------------------------------\n\n        Changes in unzip.c\n\n        2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos\n  2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz*\n  2007-2008 - Even Rouault - Remove old C style function prototypes\n  2007-2008 - Even Rouault - Add unzip support for ZIP64\n\n        Copyright (C) 2007-2008 Even Rouault\n\n\n        Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).\n  Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G\n                                should only read the compressed/uncompressed size from the Zip64 format if\n                                the size from normal header was 0xFFFFFFFF\n  Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant\n        Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required)\n                                Patch created by Daniel Borca\n\n  Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer\n\n  Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson\n\n*/\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n//#ifndef NOUNCRYPT\n//        #define NOUNCRYPT\n//#endif\n\n#include \"zlib.h\"\n#include \"unzip.h\"\n\n#ifdef STDC\n#  include <stddef.h>\n#  include <string.h>\n#  include <stdlib.h>\n#endif\n#ifdef NO_ERRNO_H\n    extern int errno;\n#else\n#   include <errno.h>\n#endif\n\n\n#ifndef local\n#  define local static\n#endif\n/* compile with -Dlocal if your debugger can't find static symbols */\n\n\n#ifndef CASESENSITIVITYDEFAULT_NO\n#  if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)\n#    define CASESENSITIVITYDEFAULT_NO\n#  endif\n#endif\n\n\n#ifndef UNZ_BUFSIZE\n#define UNZ_BUFSIZE (16384)\n#endif\n\n#ifndef UNZ_MAXFILENAMEINZIP\n#define UNZ_MAXFILENAMEINZIP (256)\n#endif\n\n#ifndef ALLOC\n# define ALLOC(size) (malloc(size))\n#endif\n#ifndef TRYFREE\n# define TRYFREE(p) {if (p) free(p);}\n#endif\n\n#define SIZECENTRALDIRITEM (0x2e)\n#define SIZEZIPLOCALHEADER (0x1e)\n\n\nconst char unz_copyright[] =\n   \" unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll\";\n\n/* unz_file_info_interntal contain internal info about a file in zipfile*/\ntypedef struct unz_file_info64_internal_s\n{\n    ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */\n} unz_file_info64_internal;\n\n\n/* file_in_zip_read_info_s contain internal information about a file in zipfile,\n    when reading and decompress it */\ntypedef struct\n{\n    char  *read_buffer;         /* internal buffer for compressed data */\n    z_stream stream;            /* zLib stream structure for inflate */\n\n#ifdef HAVE_BZIP2\n    bz_stream bstream;          /* bzLib stream structure for bziped */\n#endif\n\n    ZPOS64_T pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/\n    uLong stream_initialised;   /* flag set if stream structure is initialised*/\n\n    ZPOS64_T offset_local_extrafield;/* offset of the local extra field */\n    uInt  size_local_extrafield;/* size of the local extra field */\n    ZPOS64_T pos_local_extrafield;   /* position in the local extra field in read*/\n    ZPOS64_T total_out_64;\n\n    uLong crc32;                /* crc32 of all data uncompressed */\n    uLong crc32_wait;           /* crc32 we must obtain after decompress all */\n    ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */\n    ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/\n    zlib_filefunc64_32_def z_filefunc;\n    voidpf filestream;        /* io structore of the zipfile */\n    uLong compression_method;   /* compression method (0==store) */\n    ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/\n    int   raw;\n} file_in_zip64_read_info_s;\n\n\n/* unz64_s contain internal information about the zipfile\n*/\ntypedef struct\n{\n    zlib_filefunc64_32_def z_filefunc;\n    int is64bitOpenFunction;\n    voidpf filestream;        /* io structore of the zipfile */\n    unz_global_info64 gi;       /* public global information */\n    ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/\n    ZPOS64_T num_file;             /* number of the current file in the zipfile*/\n    ZPOS64_T pos_in_central_dir;   /* pos of the current file in the central dir*/\n    ZPOS64_T current_file_ok;      /* flag about the usability of the current file*/\n    ZPOS64_T central_pos;          /* position of the beginning of the central dir*/\n\n    ZPOS64_T size_central_dir;     /* size of the central directory  */\n    ZPOS64_T offset_central_dir;   /* offset of start of central directory with\n                                   respect to the starting disk number */\n\n    unz_file_info64 cur_file_info; /* public info about the current file in zip*/\n    unz_file_info64_internal cur_file_info_internal; /* private info about it*/\n    file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current\n                                        file if we are decompressing it */\n    int encrypted;\n\n    int isZip64;\n\n#    ifndef NOUNCRYPT\n    unsigned long keys[3];     /* keys defining the pseudo-random sequence */\n    const unsigned long* pcrc_32_tab;\n#    endif\n} unz64_s;\n\n\n#ifndef NOUNCRYPT\n#include \"crypt.h\"\n#endif\n\n/* ===========================================================================\n     Read a byte from a gz_stream; update next_in and avail_in. Return EOF\n   for end of file.\n   IN assertion: the stream s has been sucessfully opened for reading.\n*/\n\n\nlocal int unz64local_getByte OF((\n    const zlib_filefunc64_32_def* pzlib_filefunc_def,\n    voidpf filestream,\n    int *pi));\n\nlocal int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)\n{\n    unsigned char c;\n    int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);\n    if (err==1)\n    {\n        *pi = (int)c;\n        return UNZ_OK;\n    }\n    else\n    {\n        if (ZERROR64(*pzlib_filefunc_def,filestream))\n            return UNZ_ERRNO;\n        else\n            return UNZ_EOF;\n    }\n}\n\n\n/* ===========================================================================\n   Reads a long in LSB order from the given gz_stream. Sets\n*/\nlocal int unz64local_getShort OF((\n    const zlib_filefunc64_32_def* pzlib_filefunc_def,\n    voidpf filestream,\n    uLong *pX));\n\nlocal int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def,\n                             voidpf filestream,\n                             uLong *pX)\n{\n    uLong x ;\n    int i = 0;\n    int err;\n\n    err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x = (uLong)i;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((uLong)i)<<8;\n\n    if (err==UNZ_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n}\n\nlocal int unz64local_getLong OF((\n    const zlib_filefunc64_32_def* pzlib_filefunc_def,\n    voidpf filestream,\n    uLong *pX));\n\nlocal int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def,\n                            voidpf filestream,\n                            uLong *pX)\n{\n    uLong x ;\n    int i = 0;\n    int err;\n\n    err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x = (uLong)i;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((uLong)i)<<8;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((uLong)i)<<16;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<24;\n\n    if (err==UNZ_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n}\n\nlocal int unz64local_getLong64 OF((\n    const zlib_filefunc64_32_def* pzlib_filefunc_def,\n    voidpf filestream,\n    ZPOS64_T *pX));\n\n\nlocal int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def,\n                            voidpf filestream,\n                            ZPOS64_T *pX)\n{\n    ZPOS64_T x ;\n    int i = 0;\n    int err;\n\n    err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x = (ZPOS64_T)i;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((ZPOS64_T)i)<<8;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((ZPOS64_T)i)<<16;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((ZPOS64_T)i)<<24;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((ZPOS64_T)i)<<32;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((ZPOS64_T)i)<<40;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((ZPOS64_T)i)<<48;\n\n    if (err==UNZ_OK)\n        err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x |= ((ZPOS64_T)i)<<56;\n\n    if (err==UNZ_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n}\n\n/* My own strcmpi / strcasecmp */\nlocal int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2)\n{\n    for (;;)\n    {\n        char c1=*(fileName1++);\n        char c2=*(fileName2++);\n        if ((c1>='a') && (c1<='z'))\n            c1 -= 0x20;\n        if ((c2>='a') && (c2<='z'))\n            c2 -= 0x20;\n        if (c1=='\\0')\n            return ((c2=='\\0') ? 0 : -1);\n        if (c2=='\\0')\n            return 1;\n        if (c1<c2)\n            return -1;\n        if (c1>c2)\n            return 1;\n    }\n}\n\n\n#ifdef  CASESENSITIVITYDEFAULT_NO\n#define CASESENSITIVITYDEFAULTVALUE 2\n#else\n#define CASESENSITIVITYDEFAULTVALUE 1\n#endif\n\n#ifndef STRCMPCASENOSENTIVEFUNCTION\n#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal\n#endif\n\n/*\n   Compare two filename (fileName1,fileName2).\n   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)\n   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi\n                                                                or strcasecmp)\n   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system\n        (like 1 on Unix, 2 on Windows)\n\n*/\nextern int ZEXPORT unzStringFileNameCompare (const char*  fileName1,\n                                                 const char*  fileName2,\n                                                 int iCaseSensitivity)\n\n{\n    if (iCaseSensitivity==0)\n        iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;\n\n    if (iCaseSensitivity==1)\n        return strcmp(fileName1,fileName2);\n\n    return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);\n}\n\n#ifndef BUFREADCOMMENT\n#define BUFREADCOMMENT (0x400)\n#endif\n\n/*\n  Locate the Central directory of a zipfile (at the end, just before\n    the global comment)\n*/\nlocal ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));\nlocal ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)\n{\n    unsigned char* buf;\n    ZPOS64_T uSizeFile;\n    ZPOS64_T uBackRead;\n    ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */\n    ZPOS64_T uPosFound=0;\n\n    if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)\n        return 0;\n\n\n    uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);\n\n    if (uMaxBack>uSizeFile)\n        uMaxBack = uSizeFile;\n\n    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);\n    if (buf==NULL)\n        return 0;\n\n    uBackRead = 4;\n    while (uBackRead<uMaxBack)\n    {\n        uLong uReadSize;\n        ZPOS64_T uReadPos ;\n        int i;\n        if (uBackRead+BUFREADCOMMENT>uMaxBack)\n            uBackRead = uMaxBack;\n        else\n            uBackRead+=BUFREADCOMMENT;\n        uReadPos = uSizeFile-uBackRead ;\n\n        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?\n                     (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);\n        if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n            break;\n\n        if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)\n            break;\n\n        for (i=(int)uReadSize-3; (i--)>0;)\n            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&\n                ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))\n            {\n                uPosFound = uReadPos+i;\n                break;\n            }\n\n        if (uPosFound!=0)\n            break;\n    }\n    TRYFREE(buf);\n    return uPosFound;\n}\n\n\n/*\n  Locate the Central directory 64 of a zipfile (at the end, just before\n    the global comment)\n*/\nlocal ZPOS64_T unz64local_SearchCentralDir64 OF((\n    const zlib_filefunc64_32_def* pzlib_filefunc_def,\n    voidpf filestream));\n\nlocal ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def,\n                                      voidpf filestream)\n{\n    unsigned char* buf;\n    ZPOS64_T uSizeFile;\n    ZPOS64_T uBackRead;\n    ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */\n    ZPOS64_T uPosFound=0;\n    uLong uL;\n                ZPOS64_T relativeOffset;\n\n    if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)\n        return 0;\n\n\n    uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);\n\n    if (uMaxBack>uSizeFile)\n        uMaxBack = uSizeFile;\n\n    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);\n    if (buf==NULL)\n        return 0;\n\n    uBackRead = 4;\n    while (uBackRead<uMaxBack)\n    {\n        uLong uReadSize;\n        ZPOS64_T uReadPos;\n        int i;\n        if (uBackRead+BUFREADCOMMENT>uMaxBack)\n            uBackRead = uMaxBack;\n        else\n            uBackRead+=BUFREADCOMMENT;\n        uReadPos = uSizeFile-uBackRead ;\n\n        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?\n                     (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);\n        if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n            break;\n\n        if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)\n            break;\n\n        for (i=(int)uReadSize-3; (i--)>0;)\n            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&\n                ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))\n            {\n                uPosFound = uReadPos+i;\n                break;\n            }\n\n        if (uPosFound!=0)\n            break;\n    }\n    TRYFREE(buf);\n    if (uPosFound == 0)\n        return 0;\n\n    /* Zip64 end of central directory locator */\n    if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)\n        return 0;\n\n    /* the signature, already checked */\n    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)\n        return 0;\n\n    /* number of the disk with the start of the zip64 end of  central directory */\n    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)\n        return 0;\n    if (uL != 0)\n        return 0;\n\n    /* relative offset of the zip64 end of central directory record */\n    if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)\n        return 0;\n\n    /* total number of disks */\n    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)\n        return 0;\n    if (uL != 1)\n        return 0;\n\n    /* Goto end of central directory record */\n    if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)\n        return 0;\n\n     /* the signature */\n    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)\n        return 0;\n\n    if (uL != 0x06064b50)\n        return 0;\n\n    return relativeOffset;\n}\n\n/*\n  Open a Zip file. path contain the full pathname (by example,\n     on a Windows NT computer \"c:\\\\test\\\\zlib114.zip\" or on an Unix computer\n     \"zlib/zlib114.zip\".\n     If the zipfile cannot be opened (file doesn't exist or in not valid), the\n       return value is NULL.\n     Else, the return value is a unzFile Handle, usable with other function\n       of this unzip package.\n*/\nlocal unzFile unzOpenInternal (const void *path,\n                               zlib_filefunc64_32_def* pzlib_filefunc64_32_def,\n                               int is64bitOpenFunction)\n{\n    unz64_s us;\n    unz64_s *s;\n    ZPOS64_T central_pos;\n    uLong   uL;\n\n    uLong number_disk;          /* number of the current dist, used for\n                                   spaning ZIP, unsupported, always 0*/\n    uLong number_disk_with_CD;  /* number the the disk with central dir, used\n                                   for spaning ZIP, unsupported, always 0*/\n    ZPOS64_T number_entry_CD;      /* total number of entries in\n                                   the central dir\n                                   (same than number_entry on nospan) */\n\n    int err=UNZ_OK;\n\n    if (unz_copyright[0]!=' ')\n        return NULL;\n\n    us.z_filefunc.zseek32_file = NULL;\n    us.z_filefunc.ztell32_file = NULL;\n    if (pzlib_filefunc64_32_def==NULL)\n        fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);\n    else\n        us.z_filefunc = *pzlib_filefunc64_32_def;\n    us.is64bitOpenFunction = is64bitOpenFunction;\n\n\n\n    us.filestream = ZOPEN64(us.z_filefunc,\n                                                 path,\n                                                 ZLIB_FILEFUNC_MODE_READ |\n                                                 ZLIB_FILEFUNC_MODE_EXISTING);\n    if (us.filestream==NULL)\n        return NULL;\n\n    central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);\n    if (central_pos)\n    {\n        uLong uS;\n        ZPOS64_T uL64;\n\n        us.isZip64 = 1;\n\n        if (ZSEEK64(us.z_filefunc, us.filestream,\n                                      central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n        err=UNZ_ERRNO;\n\n        /* the signature, already checked */\n        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* size of zip64 end of central directory record */\n        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* version made by */\n        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* version needed to extract */\n        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* number of this disk */\n        if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* number of the disk with the start of the central directory */\n        if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* total number of entries in the central directory on this disk */\n        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* total number of entries in the central directory */\n        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        if ((number_entry_CD!=us.gi.number_entry) ||\n            (number_disk_with_CD!=0) ||\n            (number_disk!=0))\n            err=UNZ_BADZIPFILE;\n\n        /* size of the central directory */\n        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* offset of start of central directory with respect to the\n          starting disk number */\n        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        us.gi.size_comment = 0;\n    }\n    else\n    {\n        central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);\n        if (central_pos==0)\n            err=UNZ_ERRNO;\n\n        us.isZip64 = 0;\n\n        if (ZSEEK64(us.z_filefunc, us.filestream,\n                                        central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n            err=UNZ_ERRNO;\n\n        /* the signature, already checked */\n        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* number of this disk */\n        if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* number of the disk with the start of the central directory */\n        if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)\n            err=UNZ_ERRNO;\n\n        /* total number of entries in the central dir on this disk */\n        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)\n            err=UNZ_ERRNO;\n        us.gi.number_entry = uL;\n\n        /* total number of entries in the central dir */\n        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)\n            err=UNZ_ERRNO;\n        number_entry_CD = uL;\n\n        if ((number_entry_CD!=us.gi.number_entry) ||\n            (number_disk_with_CD!=0) ||\n            (number_disk!=0))\n            err=UNZ_BADZIPFILE;\n\n        /* size of the central directory */\n        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)\n            err=UNZ_ERRNO;\n        us.size_central_dir = uL;\n\n        /* offset of start of central directory with respect to the\n            starting disk number */\n        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)\n            err=UNZ_ERRNO;\n        us.offset_central_dir = uL;\n\n        /* zipfile comment length */\n        if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)\n            err=UNZ_ERRNO;\n    }\n\n    if ((central_pos<us.offset_central_dir+us.size_central_dir) &&\n        (err==UNZ_OK))\n        err=UNZ_BADZIPFILE;\n\n    if (err!=UNZ_OK)\n    {\n        ZCLOSE64(us.z_filefunc, us.filestream);\n        return NULL;\n    }\n\n    us.byte_before_the_zipfile = central_pos -\n                            (us.offset_central_dir+us.size_central_dir);\n    us.central_pos = central_pos;\n    us.pfile_in_zip_read = NULL;\n    us.encrypted = 0;\n\n\n    s=(unz64_s*)ALLOC(sizeof(unz64_s));\n    if( s != NULL)\n    {\n        *s=us;\n        unzGoToFirstFile((unzFile)s);\n    }\n    return (unzFile)s;\n}\n\n\nextern unzFile ZEXPORT unzOpen2 (const char *path,\n                                        zlib_filefunc_def* pzlib_filefunc32_def)\n{\n    if (pzlib_filefunc32_def != NULL)\n    {\n        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;\n        fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);\n        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0);\n    }\n    else\n        return unzOpenInternal(path, NULL, 0);\n}\n\nextern unzFile ZEXPORT unzOpen2_64 (const void *path,\n                                     zlib_filefunc64_def* pzlib_filefunc_def)\n{\n    if (pzlib_filefunc_def != NULL)\n    {\n        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;\n        zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;\n        zlib_filefunc64_32_def_fill.ztell32_file = NULL;\n        zlib_filefunc64_32_def_fill.zseek32_file = NULL;\n        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1);\n    }\n    else\n        return unzOpenInternal(path, NULL, 1);\n}\n\nextern unzFile ZEXPORT unzOpen (const char *path)\n{\n    return unzOpenInternal(path, NULL, 0);\n}\n\nextern unzFile ZEXPORT unzOpen64 (const void *path)\n{\n    return unzOpenInternal(path, NULL, 1);\n}\n\n/*\n  Close a ZipFile opened with unzipOpen.\n  If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),\n    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.\n  return UNZ_OK if there is no problem. */\nextern int ZEXPORT unzClose (unzFile file)\n{\n    unz64_s* s;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n\n    if (s->pfile_in_zip_read!=NULL)\n        unzCloseCurrentFile(file);\n\n    ZCLOSE64(s->z_filefunc, s->filestream);\n    TRYFREE(s);\n    return UNZ_OK;\n}\n\n\n/*\n  Write info about the ZipFile in the *pglobal_info structure.\n  No preparation of the structure is needed\n  return UNZ_OK if there is no problem. */\nextern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info)\n{\n    unz64_s* s;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    *pglobal_info=s->gi;\n    return UNZ_OK;\n}\n\nextern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32)\n{\n    unz64_s* s;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    /* to do : check if number_entry is not truncated */\n    pglobal_info32->number_entry = (uLong)s->gi.number_entry;\n    pglobal_info32->size_comment = s->gi.size_comment;\n    return UNZ_OK;\n}\n/*\n   Translate date/time from Dos format to tm_unz (readable more easilty)\n*/\nlocal void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm)\n{\n    ZPOS64_T uDate;\n    uDate = (ZPOS64_T)(ulDosDate>>16);\n    ptm->tm_mday = (uInt)(uDate&0x1f) ;\n    ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;\n    ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;\n\n    ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);\n    ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20) ;\n    ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f)) ;\n}\n\n/*\n  Get Info about the current file in the zipfile, with internal only info\n*/\nlocal int unz64local_GetCurrentFileInfoInternal OF((unzFile file,\n                                                  unz_file_info64 *pfile_info,\n                                                  unz_file_info64_internal\n                                                  *pfile_info_internal,\n                                                  char *szFileName,\n                                                  uLong fileNameBufferSize,\n                                                  void *extraField,\n                                                  uLong extraFieldBufferSize,\n                                                  char *szComment,\n                                                  uLong commentBufferSize));\n\nlocal int unz64local_GetCurrentFileInfoInternal (unzFile file,\n                                                  unz_file_info64 *pfile_info,\n                                                  unz_file_info64_internal\n                                                  *pfile_info_internal,\n                                                  char *szFileName,\n                                                  uLong fileNameBufferSize,\n                                                  void *extraField,\n                                                  uLong extraFieldBufferSize,\n                                                  char *szComment,\n                                                  uLong commentBufferSize)\n{\n    unz64_s* s;\n    unz_file_info64 file_info;\n    unz_file_info64_internal file_info_internal;\n    int err=UNZ_OK;\n    uLong uMagic;\n    long lSeek=0;\n    uLong uL;\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    if (ZSEEK64(s->z_filefunc, s->filestream,\n              s->pos_in_central_dir+s->byte_before_the_zipfile,\n              ZLIB_FILEFUNC_SEEK_SET)!=0)\n        err=UNZ_ERRNO;\n\n\n    /* we check the magic */\n    if (err==UNZ_OK)\n    {\n        if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)\n            err=UNZ_ERRNO;\n        else if (uMagic!=0x02014b50)\n            err=UNZ_BADZIPFILE;\n    }\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)\n        err=UNZ_ERRNO;\n    file_info.compressed_size = uL;\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)\n        err=UNZ_ERRNO;\n    file_info.uncompressed_size = uL;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n                // relative offset of local header\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)\n        err=UNZ_ERRNO;\n    file_info_internal.offset_curfile = uL;\n\n    lSeek+=file_info.size_filename;\n    if ((err==UNZ_OK) && (szFileName!=NULL))\n    {\n        uLong uSizeRead ;\n        if (file_info.size_filename<fileNameBufferSize)\n        {\n            *(szFileName+file_info.size_filename)='\\0';\n            uSizeRead = file_info.size_filename;\n        }\n        else\n            uSizeRead = fileNameBufferSize;\n\n        if ((file_info.size_filename>0) && (fileNameBufferSize>0))\n            if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)\n                err=UNZ_ERRNO;\n        lSeek -= uSizeRead;\n    }\n\n    // Read extrafield\n    if ((err==UNZ_OK) && (extraField!=NULL))\n    {\n        ZPOS64_T uSizeRead ;\n        if (file_info.size_file_extra<extraFieldBufferSize)\n            uSizeRead = file_info.size_file_extra;\n        else\n            uSizeRead = extraFieldBufferSize;\n\n        if (lSeek!=0)\n        {\n            if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)\n                lSeek=0;\n            else\n                err=UNZ_ERRNO;\n        }\n\n        if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))\n            if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead)\n                err=UNZ_ERRNO;\n\n        lSeek += file_info.size_file_extra - (uLong)uSizeRead;\n    }\n    else\n        lSeek += file_info.size_file_extra;\n\n\n    if ((err==UNZ_OK) && (file_info.size_file_extra != 0))\n    {\n                                uLong acc = 0;\n\n        // since lSeek now points to after the extra field we need to move back\n        lSeek -= file_info.size_file_extra;\n\n        if (lSeek!=0)\n        {\n            if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)\n                lSeek=0;\n            else\n                err=UNZ_ERRNO;\n        }\n\n        while(acc < file_info.size_file_extra)\n        {\n            uLong headerId;\n                                                uLong dataSize;\n\n            if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)\n                err=UNZ_ERRNO;\n\n            if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)\n                err=UNZ_ERRNO;\n\n            /* ZIP64 extra fields */\n            if (headerId == 0x0001)\n            {\n                                                        uLong uL;\n\n                                                                if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1)\n                                                                {\n                                                                        if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)\n                                                                                        err=UNZ_ERRNO;\n                                                                }\n\n                                                                if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1)\n                                                                {\n                                                                        if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)\n                                                                                  err=UNZ_ERRNO;\n                                                                }\n\n                                                                if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1)\n                                                                {\n                                                                        /* Relative Header offset */\n                                                                        if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)\n                                                                                err=UNZ_ERRNO;\n                                                                }\n\n                                                                if(file_info.disk_num_start == (unsigned long)-1)\n                                                                {\n                                                                        /* Disk Start Number */\n                                                                        if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)\n                                                                                err=UNZ_ERRNO;\n                                                                }\n\n            }\n            else\n            {\n                if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)\n                    err=UNZ_ERRNO;\n            }\n\n            acc += 2 + 2 + dataSize;\n        }\n    }\n\n    if ((err==UNZ_OK) && (szComment!=NULL))\n    {\n        uLong uSizeRead ;\n        if (file_info.size_file_comment<commentBufferSize)\n        {\n            *(szComment+file_info.size_file_comment)='\\0';\n            uSizeRead = file_info.size_file_comment;\n        }\n        else\n            uSizeRead = commentBufferSize;\n\n        if (lSeek!=0)\n        {\n            if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)\n\t\t\t{\n#ifndef __clang_analyzer__\n                lSeek=0;\n#endif\n\t\t\t}\n            else\n                err=UNZ_ERRNO;\n        }\n\n        if ((file_info.size_file_comment>0) && (commentBufferSize>0))\n            if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)\n                err=UNZ_ERRNO;\n#ifndef __clang_analyzer__\n        lSeek+=file_info.size_file_comment - uSizeRead;\n#endif\n    }\n#ifndef __clang_analyzer__\n    else\n        lSeek+=file_info.size_file_comment;\n#endif\n\n\n    if ((err==UNZ_OK) && (pfile_info!=NULL))\n        *pfile_info=file_info;\n\n    if ((err==UNZ_OK) && (pfile_info_internal!=NULL))\n        *pfile_info_internal=file_info_internal;\n\n    return err;\n}\n\n\n\n/*\n  Write info about the ZipFile in the *pglobal_info structure.\n  No preparation of the structure is needed\n  return UNZ_OK if there is no problem.\n*/\nextern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file,\n                                          unz_file_info64 * pfile_info,\n                                          char * szFileName, uLong fileNameBufferSize,\n                                          void *extraField, uLong extraFieldBufferSize,\n                                          char* szComment,  uLong commentBufferSize)\n{\n    return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL,\n                                                szFileName,fileNameBufferSize,\n                                                extraField,extraFieldBufferSize,\n                                                szComment,commentBufferSize);\n}\n\nextern int ZEXPORT unzGetCurrentFileInfo (unzFile file,\n                                          unz_file_info * pfile_info,\n                                          char * szFileName, uLong fileNameBufferSize,\n                                          void *extraField, uLong extraFieldBufferSize,\n                                          char* szComment,  uLong commentBufferSize)\n{\n    int err;\n    unz_file_info64 file_info64;\n    err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL,\n                                                szFileName,fileNameBufferSize,\n                                                extraField,extraFieldBufferSize,\n                                                szComment,commentBufferSize);\n    if (err==UNZ_OK)\n    {\n        pfile_info->version = file_info64.version;\n        pfile_info->version_needed = file_info64.version_needed;\n        pfile_info->flag = file_info64.flag;\n        pfile_info->compression_method = file_info64.compression_method;\n        pfile_info->dosDate = file_info64.dosDate;\n        pfile_info->crc = file_info64.crc;\n\n        pfile_info->size_filename = file_info64.size_filename;\n        pfile_info->size_file_extra = file_info64.size_file_extra;\n        pfile_info->size_file_comment = file_info64.size_file_comment;\n\n        pfile_info->disk_num_start = file_info64.disk_num_start;\n        pfile_info->internal_fa = file_info64.internal_fa;\n        pfile_info->external_fa = file_info64.external_fa;\n\n        pfile_info->tmu_date = file_info64.tmu_date,\n\n\n        pfile_info->compressed_size = (uLong)file_info64.compressed_size;\n        pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;\n\n    }\n    return err;\n}\n/*\n  Set the current file of the zipfile to the first file.\n  return UNZ_OK if there is no problem\n*/\nextern int ZEXPORT unzGoToFirstFile (unzFile file)\n{\n    int err=UNZ_OK;\n    unz64_s* s;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    s->pos_in_central_dir=s->offset_central_dir;\n    s->num_file=0;\n    err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n                                             &s->cur_file_info_internal,\n                                             NULL,0,NULL,0,NULL,0);\n    s->current_file_ok = (err == UNZ_OK);\n    return err;\n}\n\n/*\n  Set the current file of the zipfile to the next file.\n  return UNZ_OK if there is no problem\n  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.\n*/\nextern int ZEXPORT unzGoToNextFile (unzFile  file)\n{\n    unz64_s* s;\n    int err;\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    if (!s->current_file_ok)\n        return UNZ_END_OF_LIST_OF_FILE;\n    if (s->gi.number_entry != 0xffff)    /* 2^16 files overflow hack */\n      if (s->num_file+1==s->gi.number_entry)\n        return UNZ_END_OF_LIST_OF_FILE;\n\n    s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +\n            s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;\n    s->num_file++;\n    err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n                                               &s->cur_file_info_internal,\n                                               NULL,0,NULL,0,NULL,0);\n    s->current_file_ok = (err == UNZ_OK);\n    return err;\n}\n\n\n/*\n  Try locate the file szFileName in the zipfile.\n  For the iCaseSensitivity signification, see unzipStringFileNameCompare\n\n  return value :\n  UNZ_OK if the file is found. It becomes the current file.\n  UNZ_END_OF_LIST_OF_FILE if the file is not found\n*/\nextern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity)\n{\n    unz64_s* s;\n    int err;\n\n    /* We remember the 'current' position in the file so that we can jump\n     * back there if we fail.\n     */\n    unz_file_info64 cur_file_infoSaved;\n    unz_file_info64_internal cur_file_info_internalSaved;\n    ZPOS64_T num_fileSaved;\n    ZPOS64_T pos_in_central_dirSaved;\n\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n\n    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)\n        return UNZ_PARAMERROR;\n\n    s=(unz64_s*)file;\n    if (!s->current_file_ok)\n        return UNZ_END_OF_LIST_OF_FILE;\n\n    /* Save the current state */\n    num_fileSaved = s->num_file;\n    pos_in_central_dirSaved = s->pos_in_central_dir;\n    cur_file_infoSaved = s->cur_file_info;\n    cur_file_info_internalSaved = s->cur_file_info_internal;\n\n    err = unzGoToFirstFile(file);\n\n    while (err == UNZ_OK)\n    {\n        char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];\n        err = unzGetCurrentFileInfo64(file,NULL,\n                                    szCurrentFileName,sizeof(szCurrentFileName)-1,\n                                    NULL,0,NULL,0);\n        if (err == UNZ_OK)\n        {\n            if (unzStringFileNameCompare(szCurrentFileName,\n                                            szFileName,iCaseSensitivity)==0)\n                return UNZ_OK;\n            err = unzGoToNextFile(file);\n        }\n    }\n\n    /* We failed, so restore the state of the 'current file' to where we\n     * were.\n     */\n    s->num_file = num_fileSaved ;\n    s->pos_in_central_dir = pos_in_central_dirSaved ;\n    s->cur_file_info = cur_file_infoSaved;\n    s->cur_file_info_internal = cur_file_info_internalSaved;\n    return err;\n}\n\n\n/*\n///////////////////////////////////////////\n// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)\n// I need random access\n//\n// Further optimization could be realized by adding an ability\n// to cache the directory in memory. The goal being a single\n// comprehensive file read to put the file I need in a memory.\n*/\n\n/*\ntypedef struct unz_file_pos_s\n{\n    ZPOS64_T pos_in_zip_directory;   // offset in file\n    ZPOS64_T num_of_file;            // # of file\n} unz_file_pos;\n*/\n\nextern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos*  file_pos)\n{\n    unz64_s* s;\n\n    if (file==NULL || file_pos==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    if (!s->current_file_ok)\n        return UNZ_END_OF_LIST_OF_FILE;\n\n    file_pos->pos_in_zip_directory  = s->pos_in_central_dir;\n    file_pos->num_of_file           = s->num_file;\n\n    return UNZ_OK;\n}\n\nextern int ZEXPORT unzGetFilePos(\n    unzFile file,\n    unz_file_pos* file_pos)\n{\n    unz64_file_pos file_pos64;\n    int err = unzGetFilePos64(file,&file_pos64);\n    if (err==UNZ_OK)\n    {\n        file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;\n        file_pos->num_of_file = (uLong)file_pos64.num_of_file;\n    }\n    return err;\n}\n\nextern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos)\n{\n    unz64_s* s;\n    int err;\n\n    if (file==NULL || file_pos==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n\n    /* jump to the right spot */\n    s->pos_in_central_dir = file_pos->pos_in_zip_directory;\n    s->num_file           = file_pos->num_of_file;\n\n    /* set the current file */\n    err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n                                               &s->cur_file_info_internal,\n                                               NULL,0,NULL,0,NULL,0);\n    /* return results */\n    s->current_file_ok = (err == UNZ_OK);\n    return err;\n}\n\nextern int ZEXPORT unzGoToFilePos(\n    unzFile file,\n    unz_file_pos* file_pos)\n{\n    unz64_file_pos file_pos64;\n    if (file_pos == NULL)\n        return UNZ_PARAMERROR;\n\n    file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;\n    file_pos64.num_of_file = file_pos->num_of_file;\n    return unzGoToFilePos64(file,&file_pos64);\n}\n\n/*\n// Unzip Helper Functions - should be here?\n///////////////////////////////////////////\n*/\n\n/*\n  Read the local header of the current zipfile\n  Check the coherency of the local header and info in the end of central\n        directory about this file\n  store in *piSizeVar the size of extra info in local header\n        (filename and size of extra field data)\n*/\nlocal int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar,\n                                                    ZPOS64_T * poffset_local_extrafield,\n                                                    uInt  * psize_local_extrafield)\n{\n    uLong uMagic,uData,uFlags;\n    uLong size_filename;\n    uLong size_extra_field;\n    int err=UNZ_OK;\n\n    *piSizeVar = 0;\n    *poffset_local_extrafield = 0;\n    *psize_local_extrafield = 0;\n\n    if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +\n                                s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)\n        return UNZ_ERRNO;\n\n\n    if (err==UNZ_OK)\n    {\n        if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)\n            err=UNZ_ERRNO;\n        else if (uMagic!=0x04034b50)\n            err=UNZ_BADZIPFILE;\n    }\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)\n        err=UNZ_ERRNO;\n/*\n    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))\n        err=UNZ_BADZIPFILE;\n*/\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)\n        err=UNZ_ERRNO;\n    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))\n        err=UNZ_BADZIPFILE;\n\n    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&\n/* #ifdef HAVE_BZIP2 */\n                         (s->cur_file_info.compression_method!=Z_BZIP2ED) &&\n/* #endif */\n                         (s->cur_file_info.compression_method!=Z_DEFLATED))\n        err=UNZ_BADZIPFILE;\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */\n        err=UNZ_ERRNO;\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */\n        err=UNZ_ERRNO;\n    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0))\n        err=UNZ_BADZIPFILE;\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */\n        err=UNZ_ERRNO;\n    else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0))\n        err=UNZ_BADZIPFILE;\n\n    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */\n        err=UNZ_ERRNO;\n    else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0))\n        err=UNZ_BADZIPFILE;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)\n        err=UNZ_ERRNO;\n    else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))\n        err=UNZ_BADZIPFILE;\n\n    *piSizeVar += (uInt)size_filename;\n\n    if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)\n        err=UNZ_ERRNO;\n    *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +\n                                    SIZEZIPLOCALHEADER + size_filename;\n    *psize_local_extrafield = (uInt)size_extra_field;\n\n    *piSizeVar += (uInt)size_extra_field;\n\n    return err;\n}\n\n/*\n  Open for reading data the current file in the zipfile.\n  If there is no error and the file is opened, the return value is UNZ_OK.\n*/\nextern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method,\n                                            int* level, int raw, const char* password)\n{\n    int err=UNZ_OK;\n    uInt iSizeVar;\n    unz64_s* s;\n    file_in_zip64_read_info_s* pfile_in_zip_read_info;\n    ZPOS64_T offset_local_extrafield;  /* offset of the local extra field */\n    uInt  size_local_extrafield;    /* size of the local extra field */\n#    ifndef NOUNCRYPT\n    char source[12];\n#    else\n    if (password != NULL)\n        return UNZ_PARAMERROR;\n#    endif\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    if (!s->current_file_ok)\n        return UNZ_PARAMERROR;\n\n    if (s->pfile_in_zip_read != NULL)\n        unzCloseCurrentFile(file);\n\n    if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)\n        return UNZ_BADZIPFILE;\n\n    pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_INTERNALERROR;\n\n    pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);\n    pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;\n    pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;\n    pfile_in_zip_read_info->pos_local_extrafield=0;\n    pfile_in_zip_read_info->raw=raw;\n\n    if (pfile_in_zip_read_info->read_buffer==NULL)\n    {\n        TRYFREE(pfile_in_zip_read_info);\n        return UNZ_INTERNALERROR;\n    }\n\n    pfile_in_zip_read_info->stream_initialised=0;\n\n    if (method!=NULL)\n        *method = (int)s->cur_file_info.compression_method;\n\n    if (level!=NULL)\n    {\n        *level = 6;\n        switch (s->cur_file_info.flag & 0x06)\n        {\n          case 6 : *level = 1; break;\n          case 4 : *level = 2; break;\n          case 2 : *level = 9; break;\n        }\n    }\n\n    if ((s->cur_file_info.compression_method!=0) &&\n/* #ifdef HAVE_BZIP2 */\n        (s->cur_file_info.compression_method!=Z_BZIP2ED) &&\n/* #endif */\n        (s->cur_file_info.compression_method!=Z_DEFLATED))\n\t{\n#ifndef __clang_analyzer__\n        err=UNZ_BADZIPFILE;\n#endif\n\t}\n\n    pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;\n    pfile_in_zip_read_info->crc32=0;\n    pfile_in_zip_read_info->total_out_64=0;\n    pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;\n    pfile_in_zip_read_info->filestream=s->filestream;\n    pfile_in_zip_read_info->z_filefunc=s->z_filefunc;\n#ifndef __clang_analyzer__\n    pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;\n#endif\n\n    pfile_in_zip_read_info->stream.total_out = 0;\n\n    if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw))\n    {\n#ifdef HAVE_BZIP2\n      pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;\n      pfile_in_zip_read_info->bstream.bzfree = (free_func)0;\n      pfile_in_zip_read_info->bstream.opaque = (voidpf)0;\n      pfile_in_zip_read_info->bstream.state = (voidpf)0;\n\n      pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;\n      pfile_in_zip_read_info->stream.zfree = (free_func)0;\n      pfile_in_zip_read_info->stream.opaque = (voidpf)0;\n      pfile_in_zip_read_info->stream.next_in = (voidpf)0;\n      pfile_in_zip_read_info->stream.avail_in = 0;\n\n      err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);\n      if (err == Z_OK)\n        pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;\n      else\n      {\n        TRYFREE(pfile_in_zip_read_info);\n        return err;\n      }\n#else\n      pfile_in_zip_read_info->raw=1;\n#endif\n    }\n    else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))\n    {\n      pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;\n      pfile_in_zip_read_info->stream.zfree = (free_func)0;\n      pfile_in_zip_read_info->stream.opaque = (voidpf)0;\n      pfile_in_zip_read_info->stream.next_in = 0;\n      pfile_in_zip_read_info->stream.avail_in = 0;\n\n      err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);\n      if (err == Z_OK)\n        pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;\n      else\n      {\n        TRYFREE(pfile_in_zip_read_info);\n        return err;\n      }\n        /* windowBits is passed < 0 to tell that there is no zlib header.\n         * Note that in this case inflate *requires* an extra \"dummy\" byte\n         * after the compressed stream in order to complete decompression and\n         * return Z_STREAM_END.\n         * In unzip, i don't wait absolutely Z_STREAM_END because I known the\n         * size of both compressed and uncompressed data\n         */\n    }\n    pfile_in_zip_read_info->rest_read_compressed =\n            s->cur_file_info.compressed_size ;\n    pfile_in_zip_read_info->rest_read_uncompressed =\n            s->cur_file_info.uncompressed_size ;\n\n\n    pfile_in_zip_read_info->pos_in_zipfile =\n            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +\n              iSizeVar;\n\n    pfile_in_zip_read_info->stream.avail_in = (uInt)0;\n\n    s->pfile_in_zip_read = pfile_in_zip_read_info;\n                s->encrypted = 0;\n\n#    ifndef NOUNCRYPT\n    if (password != NULL)\n    {\n        int i;\n        s->pcrc_32_tab = (const unsigned long*)get_crc_table();\n        init_keys(password,s->keys,s->pcrc_32_tab);\n        if (ZSEEK64(s->z_filefunc, s->filestream,\n                  s->pfile_in_zip_read->pos_in_zipfile +\n                     s->pfile_in_zip_read->byte_before_the_zipfile,\n                  SEEK_SET)!=0)\n            return UNZ_INTERNALERROR;\n        if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12)\n            return UNZ_INTERNALERROR;\n\n        for (i = 0; i<12; i++)\n            zdecode(s->keys,s->pcrc_32_tab,source[i]);\n\n        s->pfile_in_zip_read->pos_in_zipfile+=12;\n        s->encrypted=1;\n    }\n#    endif\n\n\n    return UNZ_OK;\n}\n\nextern int ZEXPORT unzOpenCurrentFile (unzFile file)\n{\n    return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);\n}\n\nextern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char*  password)\n{\n    return unzOpenCurrentFile3(file, NULL, NULL, 0, password);\n}\n\nextern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw)\n{\n    return unzOpenCurrentFile3(file, method, level, raw, NULL);\n}\n\n/** Addition for GDAL : START */\n\nextern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file)\n{\n    unz64_s* s;\n    file_in_zip64_read_info_s* pfile_in_zip_read_info;\n    s=(unz64_s*)file;\n    if (file==NULL)\n        return 0; //UNZ_PARAMERROR;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n    if (pfile_in_zip_read_info==NULL)\n        return 0; //UNZ_PARAMERROR;\n    return pfile_in_zip_read_info->pos_in_zipfile +\n                         pfile_in_zip_read_info->byte_before_the_zipfile;\n}\n\n/** Addition for GDAL : END */\n\n/*\n  Read bytes from the current file.\n  buf contain buffer where data must be copied\n  len the size of buf.\n\n  return the number of byte copied if somes bytes are copied\n  return 0 if the end of file was reached\n  return <0 with error code if there is an error\n    (UNZ_ERRNO for IO error, or zLib error for uncompress error)\n*/\nextern int ZEXPORT unzReadCurrentFile  (unzFile file, voidp buf, unsigned len)\n{\n    int err=UNZ_OK;\n    uInt iRead = 0;\n    unz64_s* s;\n    file_in_zip64_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n\n    if (pfile_in_zip_read_info->read_buffer == NULL)\n        return UNZ_END_OF_LIST_OF_FILE;\n    if (len==0)\n        return 0;\n\n    pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;\n\n    pfile_in_zip_read_info->stream.avail_out = (uInt)len;\n\n    // NOTE:\n    // This bit of code seems to try to set the amount of space in the output buffer based on the\n    // value stored in the headers stored in the .zip file. However, if those values are incorrect\n    // it may result in a loss of data when uncompresssing that file. The compressed data is still\n    // legit and will deflate without knowing the uncompressed code so this tidbit is unnecessary and\n    // may cause issues for some .zip files.\n    //\n    // It's removed in here to fix those issues.\n    //\n    // See: https://github.com/samsoffes/ssziparchive/issues/16\n    //\n    \n    /*\n    if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&\n        (!(pfile_in_zip_read_info->raw)))\n        pfile_in_zip_read_info->stream.avail_out =\n            (uInt)pfile_in_zip_read_info->rest_read_uncompressed;\n     */\n\n    if ((len>pfile_in_zip_read_info->rest_read_compressed+\n           pfile_in_zip_read_info->stream.avail_in) &&\n         (pfile_in_zip_read_info->raw))\n        pfile_in_zip_read_info->stream.avail_out =\n            (uInt)pfile_in_zip_read_info->rest_read_compressed+\n            pfile_in_zip_read_info->stream.avail_in;\n\n    while (pfile_in_zip_read_info->stream.avail_out>0)\n    {\n        if ((pfile_in_zip_read_info->stream.avail_in==0) &&\n            (pfile_in_zip_read_info->rest_read_compressed>0))\n        {\n            uInt uReadThis = UNZ_BUFSIZE;\n            if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)\n                uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;\n            if (uReadThis == 0)\n                return UNZ_EOF;\n            if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,\n                      pfile_in_zip_read_info->filestream,\n                      pfile_in_zip_read_info->pos_in_zipfile +\n                         pfile_in_zip_read_info->byte_before_the_zipfile,\n                         ZLIB_FILEFUNC_SEEK_SET)!=0)\n                return UNZ_ERRNO;\n            if (ZREAD64(pfile_in_zip_read_info->z_filefunc,\n                      pfile_in_zip_read_info->filestream,\n                      pfile_in_zip_read_info->read_buffer,\n                      uReadThis)!=uReadThis)\n                return UNZ_ERRNO;\n\n\n#            ifndef NOUNCRYPT\n            if(s->encrypted)\n            {\n                uInt i;\n                for(i=0;i<uReadThis;i++)\n                  pfile_in_zip_read_info->read_buffer[i] =\n                      zdecode(s->keys,s->pcrc_32_tab,\n                              pfile_in_zip_read_info->read_buffer[i]);\n            }\n#            endif\n\n\n            pfile_in_zip_read_info->pos_in_zipfile += uReadThis;\n\n            pfile_in_zip_read_info->rest_read_compressed-=uReadThis;\n\n            pfile_in_zip_read_info->stream.next_in =\n                (Bytef*)pfile_in_zip_read_info->read_buffer;\n            pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;\n        }\n\n        if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))\n        {\n            uInt uDoCopy,i ;\n\n            if ((pfile_in_zip_read_info->stream.avail_in == 0) &&\n                (pfile_in_zip_read_info->rest_read_compressed == 0))\n                return (iRead==0) ? UNZ_EOF : iRead;\n\n            if (pfile_in_zip_read_info->stream.avail_out <\n                            pfile_in_zip_read_info->stream.avail_in)\n                uDoCopy = pfile_in_zip_read_info->stream.avail_out ;\n            else\n                uDoCopy = pfile_in_zip_read_info->stream.avail_in ;\n\n            for (i=0;i<uDoCopy;i++)\n                *(pfile_in_zip_read_info->stream.next_out+i) =\n                        *(pfile_in_zip_read_info->stream.next_in+i);\n\n            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy;\n\n            pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,\n                                pfile_in_zip_read_info->stream.next_out,\n                                uDoCopy);\n            pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;\n            pfile_in_zip_read_info->stream.avail_in -= uDoCopy;\n            pfile_in_zip_read_info->stream.avail_out -= uDoCopy;\n            pfile_in_zip_read_info->stream.next_out += uDoCopy;\n            pfile_in_zip_read_info->stream.next_in += uDoCopy;\n            pfile_in_zip_read_info->stream.total_out += uDoCopy;\n            iRead += uDoCopy;\n        }\n        else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED)\n        {\n#ifdef HAVE_BZIP2\n            uLong uTotalOutBefore,uTotalOutAfter;\n            const Bytef *bufBefore;\n            uLong uOutThis;\n\n            pfile_in_zip_read_info->bstream.next_in        = (char*)pfile_in_zip_read_info->stream.next_in;\n            pfile_in_zip_read_info->bstream.avail_in       = pfile_in_zip_read_info->stream.avail_in;\n            pfile_in_zip_read_info->bstream.total_in_lo32  = pfile_in_zip_read_info->stream.total_in;\n            pfile_in_zip_read_info->bstream.total_in_hi32  = 0;\n            pfile_in_zip_read_info->bstream.next_out       = (char*)pfile_in_zip_read_info->stream.next_out;\n            pfile_in_zip_read_info->bstream.avail_out      = pfile_in_zip_read_info->stream.avail_out;\n            pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out;\n            pfile_in_zip_read_info->bstream.total_out_hi32 = 0;\n\n            uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32;\n            bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out;\n\n            err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream);\n\n            uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32;\n            uOutThis = uTotalOutAfter-uTotalOutBefore;\n\n            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;\n\n            pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis));\n            pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;\n            iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);\n\n            pfile_in_zip_read_info->stream.next_in   = (Bytef*)pfile_in_zip_read_info->bstream.next_in;\n            pfile_in_zip_read_info->stream.avail_in  = pfile_in_zip_read_info->bstream.avail_in;\n            pfile_in_zip_read_info->stream.total_in  = pfile_in_zip_read_info->bstream.total_in_lo32;\n            pfile_in_zip_read_info->stream.next_out  = (Bytef*)pfile_in_zip_read_info->bstream.next_out;\n            pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out;\n            pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32;\n\n            if (err==BZ_STREAM_END)\n              return (iRead==0) ? UNZ_EOF : iRead;\n            if (err!=BZ_OK)\n              break;\n#endif\n        } // end Z_BZIP2ED\n        else\n        {\n            ZPOS64_T uTotalOutBefore,uTotalOutAfter;\n            const Bytef *bufBefore;\n            ZPOS64_T uOutThis;\n            int flush=Z_SYNC_FLUSH;\n\n            uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;\n            bufBefore = pfile_in_zip_read_info->stream.next_out;\n\n            /*\n            if ((pfile_in_zip_read_info->rest_read_uncompressed ==\n                     pfile_in_zip_read_info->stream.avail_out) &&\n                (pfile_in_zip_read_info->rest_read_compressed == 0))\n                flush = Z_FINISH;\n            */\n            err=inflate(&pfile_in_zip_read_info->stream,flush);\n\n            if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))\n              err = Z_DATA_ERROR;\n\n            uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;\n            uOutThis = uTotalOutAfter-uTotalOutBefore;\n\n            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;\n\n            pfile_in_zip_read_info->crc32 =\n                crc32(pfile_in_zip_read_info->crc32,bufBefore,\n                        (uInt)(uOutThis));\n\n            pfile_in_zip_read_info->rest_read_uncompressed -=\n                uOutThis;\n\n            iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);\n\n            if (err==Z_STREAM_END)\n                return (iRead==0) ? UNZ_EOF : iRead;\n            if (err!=Z_OK)\n                break;\n        }\n    }\n\n    if (err==Z_OK)\n        return iRead;\n    return err;\n}\n\n\n/*\n  Give the current position in uncompressed data\n*/\nextern z_off_t ZEXPORT unztell (unzFile file)\n{\n    unz64_s* s;\n    file_in_zip64_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n    return (z_off_t)pfile_in_zip_read_info->stream.total_out;\n}\n\nextern ZPOS64_T ZEXPORT unztell64 (unzFile file)\n{\n\n    unz64_s* s;\n    file_in_zip64_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return (ZPOS64_T)-1;\n    s=(unz64_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return (ZPOS64_T)-1;\n\n    return pfile_in_zip_read_info->total_out_64;\n}\n\n\n/*\n  return 1 if the end of file was reached, 0 elsewhere\n*/\nextern int ZEXPORT unzeof (unzFile file)\n{\n    unz64_s* s;\n    file_in_zip64_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n    if (pfile_in_zip_read_info->rest_read_uncompressed == 0)\n        return 1;\n    else\n        return 0;\n}\n\n\n\n/*\nRead extra field from the current file (opened by unzOpenCurrentFile)\nThis is the local-header version of the extra field (sometimes, there is\nmore info in the local-header version than in the central-header)\n\n  if buf==NULL, it return the size of the local extra field that can be read\n\n  if buf!=NULL, len is the size of the buffer, the extra header is copied in\n    buf.\n  the return value is the number of bytes copied in buf, or (if <0)\n    the error code\n*/\nextern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len)\n{\n    unz64_s* s;\n    file_in_zip64_read_info_s* pfile_in_zip_read_info;\n    uInt read_now;\n    ZPOS64_T size_to_read;\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n    size_to_read = (pfile_in_zip_read_info->size_local_extrafield -\n                pfile_in_zip_read_info->pos_local_extrafield);\n\n    if (buf==NULL)\n        return (int)size_to_read;\n\n    if (len>size_to_read)\n        read_now = (uInt)size_to_read;\n    else\n        read_now = (uInt)len ;\n\n    if (read_now==0)\n        return 0;\n\n    if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,\n              pfile_in_zip_read_info->filestream,\n              pfile_in_zip_read_info->offset_local_extrafield +\n              pfile_in_zip_read_info->pos_local_extrafield,\n              ZLIB_FILEFUNC_SEEK_SET)!=0)\n        return UNZ_ERRNO;\n\n    if (ZREAD64(pfile_in_zip_read_info->z_filefunc,\n              pfile_in_zip_read_info->filestream,\n              buf,read_now)!=read_now)\n        return UNZ_ERRNO;\n\n    return (int)read_now;\n}\n\n/*\n  Close the file in zip opened with unzipOpenCurrentFile\n  Return UNZ_CRCERROR if all the file was read but the CRC is not good\n*/\nextern int ZEXPORT unzCloseCurrentFile (unzFile file)\n{\n    int err=UNZ_OK;\n\n    unz64_s* s;\n    file_in_zip64_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n\n    if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&\n        (!pfile_in_zip_read_info->raw))\n    {\n        if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)\n            err=UNZ_CRCERROR;\n    }\n\n\n    TRYFREE(pfile_in_zip_read_info->read_buffer);\n    pfile_in_zip_read_info->read_buffer = NULL;\n    if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)\n        inflateEnd(&pfile_in_zip_read_info->stream);\n#ifdef HAVE_BZIP2\n    else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)\n        BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);\n#endif\n\n\n    pfile_in_zip_read_info->stream_initialised = 0;\n    TRYFREE(pfile_in_zip_read_info);\n\n    s->pfile_in_zip_read=NULL;\n\n    return err;\n}\n\n\n/*\n  Get the global comment string of the ZipFile, in the szComment buffer.\n  uSizeBuf is the size of the szComment buffer.\n  return the number of byte copied or an error code <0\n*/\nextern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf)\n{\n    unz64_s* s;\n    uLong uReadThis ;\n    if (file==NULL)\n        return (int)UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n\n    uReadThis = uSizeBuf;\n    if (uReadThis>s->gi.size_comment)\n        uReadThis = s->gi.size_comment;\n\n    if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)\n        return UNZ_ERRNO;\n\n    if (uReadThis>0)\n    {\n      *szComment='\\0';\n      if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)\n        return UNZ_ERRNO;\n    }\n\n    if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))\n        *(szComment+s->gi.size_comment)='\\0';\n    return (int)uReadThis;\n}\n\n/* Additions by RX '2004 */\nextern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file)\n{\n    unz64_s* s;\n\n    if (file==NULL)\n          return 0; //UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n    if (!s->current_file_ok)\n      return 0;\n    if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)\n      if (s->num_file==s->gi.number_entry)\n         return 0;\n    return s->pos_in_central_dir;\n}\n\nextern uLong ZEXPORT unzGetOffset (unzFile file)\n{\n    ZPOS64_T offset64;\n\n    if (file==NULL)\n          return 0; //UNZ_PARAMERROR;\n    offset64 = unzGetOffset64(file);\n    return (uLong)offset64;\n}\n\nextern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos)\n{\n    unz64_s* s;\n    int err;\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz64_s*)file;\n\n    s->pos_in_central_dir = pos;\n    s->num_file = s->gi.number_entry;      /* hack */\n    err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n                                              &s->cur_file_info_internal,\n                                              NULL,0,NULL,0,NULL,0);\n    s->current_file_ok = (err == UNZ_OK);\n    return err;\n}\n\nextern int ZEXPORT unzSetOffset (unzFile file, uLong pos)\n{\n    return unzSetOffset64(file,pos);\n}\n"
  },
  {
    "path": "Revolved/minizip/unzip.h",
    "content": "/* unzip.h -- IO for uncompress .zip files using zlib\n   Version 1.1, February 14h, 2010\n   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Modifications of Unzip for Zip64\n         Copyright (C) 2007-2008 Even Rouault\n\n         Modifications for Zip64 support on both zip and unzip\n         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )\n\n         For more info read MiniZip_info.txt\n\n         ---------------------------------------------------------------------------------\n\n        Condition of use and distribution are the same than zlib :\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  ---------------------------------------------------------------------------------\n\n        Changes\n\n        See header of unzip64.c\n\n*/\n\n#ifndef _unz64_H\n#define _unz64_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef _ZLIB_H\n#include \"zlib.h\"\n#endif\n\n#ifndef  _ZLIBIOAPI_H\n#include \"ioapi.h\"\n#endif\n\n#ifdef HAVE_BZIP2\n#include \"bzlib.h\"\n#endif\n\n#define Z_BZIP2ED 12\n\n#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)\n/* like the STRICT of WIN32, we define a pointer that cannot be converted\n    from (void*) without cast */\ntypedef struct TagunzFile__ { int unused; } unzFile__;\ntypedef unzFile__ *unzFile;\n#else\ntypedef voidp unzFile;\n#endif\n\n\n#define UNZ_OK                          (0)\n#define UNZ_END_OF_LIST_OF_FILE         (-100)\n#define UNZ_ERRNO                       (Z_ERRNO)\n#define UNZ_EOF                         (0)\n#define UNZ_PARAMERROR                  (-102)\n#define UNZ_BADZIPFILE                  (-103)\n#define UNZ_INTERNALERROR               (-104)\n#define UNZ_CRCERROR                    (-105)\n\n/* tm_unz contain date/time info */\ntypedef struct tm_unz_s\n{\n    uInt tm_sec;            /* seconds after the minute - [0,59] */\n    uInt tm_min;            /* minutes after the hour - [0,59] */\n    uInt tm_hour;           /* hours since midnight - [0,23] */\n    uInt tm_mday;           /* day of the month - [1,31] */\n    uInt tm_mon;            /* months since January - [0,11] */\n    uInt tm_year;           /* years - [1980..2044] */\n} tm_unz;\n\n/* unz_global_info structure contain global data about the ZIPfile\n   These data comes from the end of central dir */\ntypedef struct unz_global_info64_s\n{\n    ZPOS64_T number_entry;         /* total number of entries in\n                                     the central dir on this disk */\n    uLong size_comment;         /* size of the global comment of the zipfile */\n} unz_global_info64;\n\ntypedef struct unz_global_info_s\n{\n    uLong number_entry;         /* total number of entries in\n                                     the central dir on this disk */\n    uLong size_comment;         /* size of the global comment of the zipfile */\n} unz_global_info;\n\n/* unz_file_info contain information about a file in the zipfile */\ntypedef struct unz_file_info64_s\n{\n    uLong version;              /* version made by                 2 bytes */\n    uLong version_needed;       /* version needed to extract       2 bytes */\n    uLong flag;                 /* general purpose bit flag        2 bytes */\n    uLong compression_method;   /* compression method              2 bytes */\n    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */\n    uLong crc;                  /* crc-32                          4 bytes */\n    ZPOS64_T compressed_size;   /* compressed size                 8 bytes */\n    ZPOS64_T uncompressed_size; /* uncompressed size               8 bytes */\n    uLong size_filename;        /* filename length                 2 bytes */\n    uLong size_file_extra;      /* extra field length              2 bytes */\n    uLong size_file_comment;    /* file comment length             2 bytes */\n\n    uLong disk_num_start;       /* disk number start               2 bytes */\n    uLong internal_fa;          /* internal file attributes        2 bytes */\n    uLong external_fa;          /* external file attributes        4 bytes */\n\n    tm_unz tmu_date;\n} unz_file_info64;\n\ntypedef struct unz_file_info_s\n{\n    uLong version;              /* version made by                 2 bytes */\n    uLong version_needed;       /* version needed to extract       2 bytes */\n    uLong flag;                 /* general purpose bit flag        2 bytes */\n    uLong compression_method;   /* compression method              2 bytes */\n    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */\n    uLong crc;                  /* crc-32                          4 bytes */\n    uLong compressed_size;      /* compressed size                 4 bytes */\n    uLong uncompressed_size;    /* uncompressed size               4 bytes */\n    uLong size_filename;        /* filename length                 2 bytes */\n    uLong size_file_extra;      /* extra field length              2 bytes */\n    uLong size_file_comment;    /* file comment length             2 bytes */\n\n    uLong disk_num_start;       /* disk number start               2 bytes */\n    uLong internal_fa;          /* internal file attributes        2 bytes */\n    uLong external_fa;          /* external file attributes        4 bytes */\n\n    tm_unz tmu_date;\n} unz_file_info;\n\nextern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,\n                                                 const char* fileName2,\n                                                 int iCaseSensitivity));\n/*\n   Compare two filename (fileName1,fileName2).\n   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)\n   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi\n                                or strcasecmp)\n   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system\n    (like 1 on Unix, 2 on Windows)\n*/\n\n\nextern unzFile ZEXPORT unzOpen OF((const char *path));\nextern unzFile ZEXPORT unzOpen64 OF((const void *path));\n/*\n  Open a Zip file. path contain the full pathname (by example,\n     on a Windows XP computer \"c:\\\\zlib\\\\zlib113.zip\" or on an Unix computer\n     \"zlib/zlib113.zip\".\n     If the zipfile cannot be opened (file don't exist or in not valid), the\n       return value is NULL.\n     Else, the return value is a unzFile Handle, usable with other function\n       of this unzip package.\n     the \"64\" function take a const void* pointer, because the path is just the\n       value passed to the open64_file_func callback.\n     Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path\n       is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*\n       does not describe the reality\n*/\n\n\nextern unzFile ZEXPORT unzOpen2 OF((const char *path,\n                                    zlib_filefunc_def* pzlib_filefunc_def));\n/*\n   Open a Zip file, like unzOpen, but provide a set of file low level API\n      for read/write the zip file (see ioapi.h)\n*/\n\nextern unzFile ZEXPORT unzOpen2_64 OF((const void *path,\n                                    zlib_filefunc64_def* pzlib_filefunc_def));\n/*\n   Open a Zip file, like unz64Open, but provide a set of file low level API\n      for read/write the zip file (see ioapi.h)\n*/\n\nextern int ZEXPORT unzClose OF((unzFile file));\n/*\n  Close a ZipFile opened with unzipOpen.\n  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),\n    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.\n  return UNZ_OK if there is no problem. */\n\nextern int ZEXPORT unzGetGlobalInfo OF((unzFile file,\n                                        unz_global_info *pglobal_info));\n\nextern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,\n                                        unz_global_info64 *pglobal_info));\n/*\n  Write info about the ZipFile in the *pglobal_info structure.\n  No preparation of the structure is needed\n  return UNZ_OK if there is no problem. */\n\n\nextern int ZEXPORT unzGetGlobalComment OF((unzFile file,\n                                           char *szComment,\n                                           uLong uSizeBuf));\n/*\n  Get the global comment string of the ZipFile, in the szComment buffer.\n  uSizeBuf is the size of the szComment buffer.\n  return the number of byte copied or an error code <0\n*/\n\n\n/***************************************************************************/\n/* Unzip package allow you browse the directory of the zipfile */\n\nextern int ZEXPORT unzGoToFirstFile OF((unzFile file));\n/*\n  Set the current file of the zipfile to the first file.\n  return UNZ_OK if there is no problem\n*/\n\nextern int ZEXPORT unzGoToNextFile OF((unzFile file));\n/*\n  Set the current file of the zipfile to the next file.\n  return UNZ_OK if there is no problem\n  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.\n*/\n\nextern int ZEXPORT unzLocateFile OF((unzFile file,\n                     const char *szFileName,\n                     int iCaseSensitivity));\n/*\n  Try locate the file szFileName in the zipfile.\n  For the iCaseSensitivity signification, see unzStringFileNameCompare\n\n  return value :\n  UNZ_OK if the file is found. It becomes the current file.\n  UNZ_END_OF_LIST_OF_FILE if the file is not found\n*/\n\n\n/* ****************************************** */\n/* Ryan supplied functions */\n/* unz_file_info contain information about a file in the zipfile */\ntypedef struct unz_file_pos_s\n{\n    uLong pos_in_zip_directory;   /* offset in zip file directory */\n    uLong num_of_file;            /* # of file */\n} unz_file_pos;\n\nextern int ZEXPORT unzGetFilePos(\n    unzFile file,\n    unz_file_pos* file_pos);\n\nextern int ZEXPORT unzGoToFilePos(\n    unzFile file,\n    unz_file_pos* file_pos);\n\ntypedef struct unz64_file_pos_s\n{\n    ZPOS64_T pos_in_zip_directory;   /* offset in zip file directory */\n    ZPOS64_T num_of_file;            /* # of file */\n} unz64_file_pos;\n\nextern int ZEXPORT unzGetFilePos64(\n    unzFile file,\n    unz64_file_pos* file_pos);\n\nextern int ZEXPORT unzGoToFilePos64(\n    unzFile file,\n    const unz64_file_pos* file_pos);\n\n/* ****************************************** */\n\nextern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,\n                         unz_file_info64 *pfile_info,\n                         char *szFileName,\n                         uLong fileNameBufferSize,\n                         void *extraField,\n                         uLong extraFieldBufferSize,\n                         char *szComment,\n                         uLong commentBufferSize));\n\nextern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,\n                         unz_file_info *pfile_info,\n                         char *szFileName,\n                         uLong fileNameBufferSize,\n                         void *extraField,\n                         uLong extraFieldBufferSize,\n                         char *szComment,\n                         uLong commentBufferSize));\n/*\n  Get Info about the current file\n  if pfile_info!=NULL, the *pfile_info structure will contain somes info about\n        the current file\n  if szFileName!=NULL, the filemane string will be copied in szFileName\n            (fileNameBufferSize is the size of the buffer)\n  if extraField!=NULL, the extra field information will be copied in extraField\n            (extraFieldBufferSize is the size of the buffer).\n            This is the Central-header version of the extra field\n  if szComment!=NULL, the comment string of the file will be copied in szComment\n            (commentBufferSize is the size of the buffer)\n*/\n\n\n/** Addition for GDAL : START */\n\nextern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));\n\n/** Addition for GDAL : END */\n\n\n/***************************************************************************/\n/* for reading the content of the current zipfile, you can open it, read data\n   from it, and close it (you can close it before reading all the file)\n   */\n\nextern int ZEXPORT unzOpenCurrentFile OF((unzFile file));\n/*\n  Open for reading data the current file in the zipfile.\n  If there is no error, the return value is UNZ_OK.\n*/\n\nextern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,\n                                                  const char* password));\n/*\n  Open for reading data the current file in the zipfile.\n  password is a crypting password\n  If there is no error, the return value is UNZ_OK.\n*/\n\nextern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,\n                                           int* method,\n                                           int* level,\n                                           int raw));\n/*\n  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)\n    if raw==1\n  *method will receive method of compression, *level will receive level of\n     compression\n  note : you can set level parameter as NULL (if you did not want known level,\n         but you CANNOT set method parameter as NULL\n*/\n\nextern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,\n                                           int* method,\n                                           int* level,\n                                           int raw,\n                                           const char* password));\n/*\n  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)\n    if raw==1\n  *method will receive method of compression, *level will receive level of\n     compression\n  note : you can set level parameter as NULL (if you did not want known level,\n         but you CANNOT set method parameter as NULL\n*/\n\n\nextern int ZEXPORT unzCloseCurrentFile OF((unzFile file));\n/*\n  Close the file in zip opened with unzOpenCurrentFile\n  Return UNZ_CRCERROR if all the file was read but the CRC is not good\n*/\n\nextern int ZEXPORT unzReadCurrentFile OF((unzFile file,\n                      voidp buf,\n                      unsigned len));\n/*\n  Read bytes from the current file (opened by unzOpenCurrentFile)\n  buf contain buffer where data must be copied\n  len the size of buf.\n\n  return the number of byte copied if somes bytes are copied\n  return 0 if the end of file was reached\n  return <0 with error code if there is an error\n    (UNZ_ERRNO for IO error, or zLib error for uncompress error)\n*/\n\nextern z_off_t ZEXPORT unztell OF((unzFile file));\n\nextern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));\n/*\n  Give the current position in uncompressed data\n*/\n\nextern int ZEXPORT unzeof OF((unzFile file));\n/*\n  return 1 if the end of file was reached, 0 elsewhere\n*/\n\nextern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,\n                                             voidp buf,\n                                             unsigned len));\n/*\n  Read extra field from the current file (opened by unzOpenCurrentFile)\n  This is the local-header version of the extra field (sometimes, there is\n    more info in the local-header version than in the central-header)\n\n  if buf==NULL, it return the size of the local extra field\n\n  if buf!=NULL, len is the size of the buffer, the extra header is copied in\n    buf.\n  the return value is the number of bytes copied in buf, or (if <0)\n    the error code\n*/\n\n/***************************************************************************/\n\n/* Get the current file offset */\nextern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);\nextern uLong ZEXPORT unzGetOffset (unzFile file);\n\n/* Set the current file offset */\nextern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);\nextern int ZEXPORT unzSetOffset (unzFile file, uLong pos);\n\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _unz64_H */\n"
  },
  {
    "path": "Revolved/minizip/zip.c",
    "content": "/* zip.c -- IO on .zip files using zlib\n   Version 1.1, February 14h, 2010\n   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Modifications for Zip64 support\n         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )\n\n         For more info read MiniZip_info.txt\n\n         Changes\n   Oct-2009 - Mathias Svensson - Remove old C style function prototypes\n   Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives\n   Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.\n   Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data\n                                 It is used when recreting zip archive with RAW when deleting items from a zip.\n                                 ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed.\n   Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required)\n   Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer\n\n*/\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include \"zlib.h\"\n#include \"zip.h\"\n\n#ifdef STDC\n#  include <stddef.h>\n#  include <string.h>\n#  include <stdlib.h>\n#endif\n#ifdef NO_ERRNO_H\n    extern int errno;\n#else\n#   include <errno.h>\n#endif\n\n\n#ifndef local\n#  define local static\n#endif\n/* compile with -Dlocal if your debugger can't find static symbols */\n\n#ifndef VERSIONMADEBY\n# define VERSIONMADEBY   (0x0) /* platform depedent */\n#endif\n\n#ifndef Z_BUFSIZE\n#define Z_BUFSIZE (64*1024) //(16384)\n#endif\n\n#ifndef Z_MAXFILENAMEINZIP\n#define Z_MAXFILENAMEINZIP (256)\n#endif\n\n#ifndef ALLOC\n# define ALLOC(size) (malloc(size))\n#endif\n#ifndef TRYFREE\n# define TRYFREE(p) {if (p) free(p);}\n#endif\n\n/*\n#define SIZECENTRALDIRITEM (0x2e)\n#define SIZEZIPLOCALHEADER (0x1e)\n*/\n\n/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */\n\n\n// NOT sure that this work on ALL platform\n#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32))\n\n#ifndef SEEK_CUR\n#define SEEK_CUR    1\n#endif\n\n#ifndef SEEK_END\n#define SEEK_END    2\n#endif\n\n#ifndef SEEK_SET\n#define SEEK_SET    0\n#endif\n\n#ifndef DEF_MEM_LEVEL\n#if MAX_MEM_LEVEL >= 8\n#  define DEF_MEM_LEVEL 8\n#else\n#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#endif\n#endif\nconst char zip_copyright[] =\" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll\";\n\n\n#define SIZEDATA_INDATABLOCK (4096-(4*4))\n\n#define LOCALHEADERMAGIC    (0x04034b50)\n#define CENTRALHEADERMAGIC  (0x02014b50)\n#define ENDHEADERMAGIC      (0x06054b50)\n#define ZIP64ENDHEADERMAGIC      (0x6064b50)\n#define ZIP64ENDLOCHEADERMAGIC   (0x7064b50)\n\n#define FLAG_LOCALHEADER_OFFSET (0x06)\n#define CRC_LOCALHEADER_OFFSET  (0x0e)\n\n#define SIZECENTRALHEADER (0x2e) /* 46 */\n\ntypedef struct linkedlist_datablock_internal_s\n{\n  struct linkedlist_datablock_internal_s* next_datablock;\n  uLong  avail_in_this_block;\n  uLong  filled_in_this_block;\n  uLong  unused; /* for future use and alignement */\n  unsigned char data[SIZEDATA_INDATABLOCK];\n} linkedlist_datablock_internal;\n\ntypedef struct linkedlist_data_s\n{\n    linkedlist_datablock_internal* first_block;\n    linkedlist_datablock_internal* last_block;\n} linkedlist_data;\n\n\ntypedef struct\n{\n    z_stream stream;            /* zLib stream structure for inflate */\n#ifdef HAVE_BZIP2\n    bz_stream bstream;          /* bzLib stream structure for bziped */\n#endif\n\n    int  stream_initialised;    /* 1 is stream is initialised */\n    uInt pos_in_buffered_data;  /* last written byte in buffered_data */\n\n    ZPOS64_T pos_local_header;     /* offset of the local header of the file\n                                     currenty writing */\n    char* central_header;       /* central header data for the current file */\n    uLong size_centralExtra;\n    uLong size_centralheader;   /* size of the central header for cur file */\n    uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */\n    uLong flag;                 /* flag of the file currently writing */\n\n    int  method;                /* compression method of file currenty wr.*/\n    int  raw;                   /* 1 for directly writing raw data */\n    Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/\n    uLong dosDate;\n    uLong crc32;\n    int  encrypt;\n    int  zip64;               /* Add ZIP64 extened information in the extra field */\n    ZPOS64_T pos_zip64extrainfo;\n    ZPOS64_T totalCompressedData;\n    ZPOS64_T totalUncompressedData;\n#ifndef NOCRYPT\n    unsigned long keys[3];     /* keys defining the pseudo-random sequence */\n    const unsigned long* pcrc_32_tab;\n    int crypt_header_size;\n#endif\n} curfile64_info;\n\ntypedef struct\n{\n    zlib_filefunc64_32_def z_filefunc;\n    voidpf filestream;        /* io structore of the zipfile */\n    linkedlist_data central_dir;/* datablock with central dir in construction*/\n    int  in_opened_file_inzip;  /* 1 if a file in the zip is currently writ.*/\n    curfile64_info ci;            /* info on the file curretly writing */\n\n    ZPOS64_T begin_pos;            /* position of the beginning of the zipfile */\n    ZPOS64_T add_position_when_writting_offset;\n    ZPOS64_T number_entry;\n\n#ifndef NO_ADDFILEINEXISTINGZIP\n    char *globalcomment;\n#endif\n\n} zip64_internal;\n\n\n#ifndef NOCRYPT\n#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED\n#include \"crypt.h\"\n#endif\n\nlocal linkedlist_datablock_internal* allocate_new_datablock()\n{\n    linkedlist_datablock_internal* ldi;\n    ldi = (linkedlist_datablock_internal*)\n                 ALLOC(sizeof(linkedlist_datablock_internal));\n    if (ldi!=NULL)\n    {\n        ldi->next_datablock = NULL ;\n        ldi->filled_in_this_block = 0 ;\n        ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;\n    }\n    return ldi;\n}\n\nlocal void free_datablock(linkedlist_datablock_internal* ldi)\n{\n    while (ldi!=NULL)\n    {\n        linkedlist_datablock_internal* ldinext = ldi->next_datablock;\n        TRYFREE(ldi);\n        ldi = ldinext;\n    }\n}\n\nlocal void init_linkedlist(linkedlist_data* ll)\n{\n    ll->first_block = ll->last_block = NULL;\n}\n\nlocal void free_linkedlist(linkedlist_data* ll)\n{\n    free_datablock(ll->first_block);\n    ll->first_block = ll->last_block = NULL;\n}\n\n\nlocal int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len)\n{\n    linkedlist_datablock_internal* ldi;\n    const unsigned char* from_copy;\n\n    if (ll==NULL)\n        return ZIP_INTERNALERROR;\n\n    if (ll->last_block == NULL)\n    {\n        ll->first_block = ll->last_block = allocate_new_datablock();\n        if (ll->first_block == NULL)\n            return ZIP_INTERNALERROR;\n    }\n\n    ldi = ll->last_block;\n    from_copy = (unsigned char*)buf;\n\n    while (len>0)\n    {\n        uInt copy_this;\n        uInt i;\n        unsigned char* to_copy;\n\n        if (ldi->avail_in_this_block==0)\n        {\n            ldi->next_datablock = allocate_new_datablock();\n            if (ldi->next_datablock == NULL)\n                return ZIP_INTERNALERROR;\n            ldi = ldi->next_datablock ;\n            ll->last_block = ldi;\n        }\n\n        if (ldi->avail_in_this_block < len)\n            copy_this = (uInt)ldi->avail_in_this_block;\n        else\n            copy_this = (uInt)len;\n\n        to_copy = &(ldi->data[ldi->filled_in_this_block]);\n\n        for (i=0;i<copy_this;i++)\n            *(to_copy+i)=*(from_copy+i);\n\n        ldi->filled_in_this_block += copy_this;\n        ldi->avail_in_this_block -= copy_this;\n        from_copy += copy_this ;\n        len -= copy_this;\n    }\n    return ZIP_OK;\n}\n\n\n\n/****************************************************************************/\n\n#ifndef NO_ADDFILEINEXISTINGZIP\n/* ===========================================================================\n   Inputs a long in LSB order to the given file\n   nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)\n*/\n\nlocal int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte));\nlocal int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)\n{\n    unsigned char buf[8];\n    int n;\n    for (n = 0; n < nbByte; n++)\n    {\n        buf[n] = (unsigned char)(x & 0xff);\n        x >>= 8;\n    }\n    if (x != 0)\n      {     /* data overflow - hack for ZIP64 (X Roche) */\n      for (n = 0; n < nbByte; n++)\n        {\n          buf[n] = 0xff;\n        }\n      }\n\n    if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte)\n        return ZIP_ERRNO;\n    else\n        return ZIP_OK;\n}\n\nlocal void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte));\nlocal void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte)\n{\n    unsigned char* buf=(unsigned char*)dest;\n    int n;\n    for (n = 0; n < nbByte; n++) {\n        buf[n] = (unsigned char)(x & 0xff);\n        x >>= 8;\n    }\n\n    if (x != 0)\n    {     /* data overflow - hack for ZIP64 */\n       for (n = 0; n < nbByte; n++)\n       {\n          buf[n] = 0xff;\n       }\n    }\n}\n\n/****************************************************************************/\n\n\nlocal uLong zip64local_TmzDateToDosDate(const tm_zip* ptm)\n{\n    uLong year = (uLong)ptm->tm_year;\n    if (year>=1980)\n        year-=1980;\n    else if (year>=80)\n        year-=80;\n    return\n      (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |\n        ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));\n}\n\n\n/****************************************************************************/\n\nlocal int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi));\n\nlocal int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi)\n{\n    unsigned char c;\n    int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);\n    if (err==1)\n    {\n        *pi = (int)c;\n        return ZIP_OK;\n    }\n    else\n    {\n        if (ZERROR64(*pzlib_filefunc_def,filestream))\n            return ZIP_ERRNO;\n        else\n            return ZIP_EOF;\n    }\n}\n\n\n/* ===========================================================================\n   Reads a long in LSB order from the given gz_stream. Sets\n*/\nlocal int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));\n\nlocal int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)\n{\n    uLong x ;\n    int i = 0;\n    int err;\n\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x = (uLong)i;\n\n    if (err==ZIP_OK)\n        err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<8;\n\n    if (err==ZIP_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n}\n\nlocal int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));\n\nlocal int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)\n{\n    uLong x ;\n    int i = 0;\n    int err;\n\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x = (uLong)i;\n\n    if (err==ZIP_OK)\n        err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<8;\n\n    if (err==ZIP_OK)\n        err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<16;\n\n    if (err==ZIP_OK)\n        err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<24;\n\n    if (err==ZIP_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n}\n\nlocal int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX));\n\n\nlocal int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)\n{\n  ZPOS64_T x;\n  int i = 0;\n  int err;\n\n  err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n  x = (ZPOS64_T)i;\n\n  if (err==ZIP_OK)\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n  x += ((ZPOS64_T)i)<<8;\n\n  if (err==ZIP_OK)\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n  x += ((ZPOS64_T)i)<<16;\n\n  if (err==ZIP_OK)\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n  x += ((ZPOS64_T)i)<<24;\n\n  if (err==ZIP_OK)\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n  x += ((ZPOS64_T)i)<<32;\n\n  if (err==ZIP_OK)\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n  x += ((ZPOS64_T)i)<<40;\n\n  if (err==ZIP_OK)\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n  x += ((ZPOS64_T)i)<<48;\n\n  if (err==ZIP_OK)\n    err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);\n  x += ((ZPOS64_T)i)<<56;\n\n  if (err==ZIP_OK)\n    *pX = x;\n  else\n    *pX = 0;\n\n  return err;\n}\n\n#ifndef BUFREADCOMMENT\n#define BUFREADCOMMENT (0x400)\n#endif\n/*\n  Locate the Central directory of a zipfile (at the end, just before\n    the global comment)\n*/\nlocal ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));\n\nlocal ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)\n{\n  unsigned char* buf;\n  ZPOS64_T uSizeFile;\n  ZPOS64_T uBackRead;\n  ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */\n  ZPOS64_T uPosFound=0;\n\n  if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)\n    return 0;\n\n\n  uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);\n\n  if (uMaxBack>uSizeFile)\n    uMaxBack = uSizeFile;\n\n  buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);\n  if (buf==NULL)\n    return 0;\n\n  uBackRead = 4;\n  while (uBackRead<uMaxBack)\n  {\n    uLong uReadSize;\n    ZPOS64_T uReadPos ;\n    int i;\n    if (uBackRead+BUFREADCOMMENT>uMaxBack)\n      uBackRead = uMaxBack;\n    else\n      uBackRead+=BUFREADCOMMENT;\n    uReadPos = uSizeFile-uBackRead ;\n\n    uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?\n      (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);\n    if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n      break;\n\n    if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)\n      break;\n\n    for (i=(int)uReadSize-3; (i--)>0;)\n      if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&\n        ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))\n      {\n        uPosFound = uReadPos+i;\n        break;\n      }\n\n      if (uPosFound!=0)\n        break;\n  }\n  TRYFREE(buf);\n  return uPosFound;\n}\n\n/*\nLocate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before\nthe global comment)\n*/\nlocal ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));\n\nlocal ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)\n{\n  unsigned char* buf;\n  ZPOS64_T uSizeFile;\n  ZPOS64_T uBackRead;\n  ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */\n  ZPOS64_T uPosFound=0;\n  uLong uL;\n  ZPOS64_T relativeOffset;\n\n  if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)\n    return 0;\n\n  uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);\n\n  if (uMaxBack>uSizeFile)\n    uMaxBack = uSizeFile;\n\n  buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);\n  if (buf==NULL)\n    return 0;\n\n  uBackRead = 4;\n  while (uBackRead<uMaxBack)\n  {\n    uLong uReadSize;\n    ZPOS64_T uReadPos;\n    int i;\n    if (uBackRead+BUFREADCOMMENT>uMaxBack)\n      uBackRead = uMaxBack;\n    else\n      uBackRead+=BUFREADCOMMENT;\n    uReadPos = uSizeFile-uBackRead ;\n\n    uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?\n      (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);\n    if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n      break;\n\n    if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)\n      break;\n\n    for (i=(int)uReadSize-3; (i--)>0;)\n    {\n      // Signature \"0x07064b50\" Zip64 end of central directory locater\n      if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))\n      {\n        uPosFound = uReadPos+i;\n        break;\n      }\n    }\n\n      if (uPosFound!=0)\n        break;\n  }\n\n  TRYFREE(buf);\n  if (uPosFound == 0)\n    return 0;\n\n  /* Zip64 end of central directory locator */\n  if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)\n    return 0;\n\n  /* the signature, already checked */\n  if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)\n    return 0;\n\n  /* number of the disk with the start of the zip64 end of  central directory */\n  if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)\n    return 0;\n  if (uL != 0)\n    return 0;\n\n  /* relative offset of the zip64 end of central directory record */\n  if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK)\n    return 0;\n\n  /* total number of disks */\n  if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)\n    return 0;\n  if (uL != 1)\n    return 0;\n\n  /* Goto Zip64 end of central directory record */\n  if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)\n    return 0;\n\n  /* the signature */\n  if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)\n    return 0;\n\n  if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'\n    return 0;\n\n  return relativeOffset;\n}\n\nint LoadCentralDirectoryRecord(zip64_internal* pziinit);\nint LoadCentralDirectoryRecord(zip64_internal* pziinit)\n{\n  int err=ZIP_OK;\n  ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/\n\n  ZPOS64_T size_central_dir;     /* size of the central directory  */\n  ZPOS64_T offset_central_dir;   /* offset of start of central directory */\n  ZPOS64_T central_pos;\n  uLong uL;\n\n  uLong number_disk;          /* number of the current dist, used for\n                              spaning ZIP, unsupported, always 0*/\n  uLong number_disk_with_CD;  /* number the the disk with central dir, used\n                              for spaning ZIP, unsupported, always 0*/\n  ZPOS64_T number_entry;\n  ZPOS64_T number_entry_CD;      /* total number of entries in\n                                the central dir\n                                (same than number_entry on nospan) */\n  uLong VersionMadeBy;\n  uLong VersionNeeded;\n  uLong size_comment;\n\n  int hasZIP64Record = 0;\n\n  // check first if we find a ZIP64 record\n  central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream);\n  if(central_pos > 0)\n  {\n    hasZIP64Record = 1;\n  }\n  else if(central_pos == 0)\n  {\n    central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream);\n  }\n\n/* disable to allow appending to empty ZIP archive\n        if (central_pos==0)\n            err=ZIP_ERRNO;\n*/\n\n  if(hasZIP64Record)\n  {\n    ZPOS64_T sizeEndOfCentralDirectory;\n    if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)\n      err=ZIP_ERRNO;\n\n    /* the signature, already checked */\n    if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* size of zip64 end of central directory record */\n    if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* version made by */\n    if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* version needed to extract */\n    if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* number of this disk */\n    if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* number of the disk with the start of the central directory */\n    if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* total number of entries in the central directory on this disk */\n    if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* total number of entries in the central directory */\n    if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))\n      err=ZIP_BADZIPFILE;\n\n    /* size of the central directory */\n    if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* offset of start of central directory with respect to the\n    starting disk number */\n    if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    // TODO..\n    // read the comment from the standard central header.\n    size_comment = 0;\n  }\n  else\n  {\n    // Read End of central Directory info\n    if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n      err=ZIP_ERRNO;\n\n    /* the signature, already checked */\n    if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* number of this disk */\n    if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* number of the disk with the start of the central directory */\n    if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)\n      err=ZIP_ERRNO;\n\n    /* total number of entries in the central dir on this disk */\n    number_entry = 0;\n    if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)\n      err=ZIP_ERRNO;\n    else\n      number_entry = uL;\n\n    /* total number of entries in the central dir */\n    number_entry_CD = 0;\n    if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)\n      err=ZIP_ERRNO;\n    else\n      number_entry_CD = uL;\n\n    if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))\n      err=ZIP_BADZIPFILE;\n\n    /* size of the central directory */\n    size_central_dir = 0;\n    if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)\n      err=ZIP_ERRNO;\n    else\n      size_central_dir = uL;\n\n    /* offset of start of central directory with respect to the starting disk number */\n    offset_central_dir = 0;\n    if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)\n      err=ZIP_ERRNO;\n    else\n      offset_central_dir = uL;\n\n\n    /* zipfile global comment length */\n    if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK)\n      err=ZIP_ERRNO;\n  }\n\n  if ((central_pos<offset_central_dir+size_central_dir) &&\n    (err==ZIP_OK))\n    err=ZIP_BADZIPFILE;\n\n  if (err!=ZIP_OK)\n  {\n    ZCLOSE64(pziinit->z_filefunc, pziinit->filestream);\n    return ZIP_ERRNO;\n  }\n\n  if (size_comment>0)\n  {\n    pziinit->globalcomment = (char*)ALLOC(size_comment+1);\n    if (pziinit->globalcomment)\n    {\n      size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment);\n      pziinit->globalcomment[size_comment]=0;\n    }\n  }\n\n  byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir);\n  pziinit->add_position_when_writting_offset = byte_before_the_zipfile;\n\n  {\n    ZPOS64_T size_central_dir_to_read = size_central_dir;\n    size_t buf_size = SIZEDATA_INDATABLOCK;\n    void* buf_read = (void*)ALLOC(buf_size);\n    if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)\n      err=ZIP_ERRNO;\n\n    while ((size_central_dir_to_read>0) && (err==ZIP_OK))\n    {\n      ZPOS64_T read_this = SIZEDATA_INDATABLOCK;\n      if (read_this > size_central_dir_to_read)\n        read_this = size_central_dir_to_read;\n\n      if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this)\n        err=ZIP_ERRNO;\n\n      if (err==ZIP_OK)\n        err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this);\n\n      size_central_dir_to_read-=read_this;\n    }\n    TRYFREE(buf_read);\n  }\n  pziinit->begin_pos = byte_before_the_zipfile;\n  pziinit->number_entry = number_entry_CD;\n\n  if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0)\n    err=ZIP_ERRNO;\n\n  return err;\n}\n\n\n#endif /* !NO_ADDFILEINEXISTINGZIP*/\n\n\n/************************************************************/\nextern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def);\nextern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def)\n{\n    zip64_internal ziinit;\n    zip64_internal* zi;\n    int err=ZIP_OK;\n\n    ziinit.z_filefunc.zseek32_file = NULL;\n    ziinit.z_filefunc.ztell32_file = NULL;\n    if (pzlib_filefunc64_32_def==NULL)\n        fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64);\n    else\n        ziinit.z_filefunc = *pzlib_filefunc64_32_def;\n\n    ziinit.filestream = ZOPEN64(ziinit.z_filefunc,\n                  pathname,\n                  (append == APPEND_STATUS_CREATE) ?\n                  (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :\n                    (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));\n\n    if (ziinit.filestream == NULL)\n        return NULL;\n\n    if (append == APPEND_STATUS_CREATEAFTER)\n        ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END);\n\n    ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream);\n    ziinit.in_opened_file_inzip = 0;\n    ziinit.ci.stream_initialised = 0;\n    ziinit.number_entry = 0;\n    ziinit.add_position_when_writting_offset = 0;\n    init_linkedlist(&(ziinit.central_dir));\n\n\n\n    zi = (zip64_internal*)ALLOC(sizeof(zip64_internal));\n    if (zi==NULL)\n    {\n        ZCLOSE64(ziinit.z_filefunc,ziinit.filestream);\n        return NULL;\n    }\n\n    /* now we add file in a zipfile */\n#    ifndef NO_ADDFILEINEXISTINGZIP\n    ziinit.globalcomment = NULL;\n    if (append == APPEND_STATUS_ADDINZIP)\n    {\n      // Read and Cache Central Directory Records\n      err = LoadCentralDirectoryRecord(&ziinit);\n    }\n\n    if (globalcomment)\n    {\n      *globalcomment = ziinit.globalcomment;\n    }\n#    endif /* !NO_ADDFILEINEXISTINGZIP*/\n\n    if (err != ZIP_OK)\n    {\n#    ifndef NO_ADDFILEINEXISTINGZIP\n        TRYFREE(ziinit.globalcomment);\n#    endif /* !NO_ADDFILEINEXISTINGZIP*/\n        TRYFREE(zi);\n        return NULL;\n    }\n    else\n    {\n        *zi = ziinit;\n        return (zipFile)zi;\n    }\n}\n\nextern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def)\n{\n    if (pzlib_filefunc32_def != NULL)\n    {\n        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;\n        fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);\n        return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);\n    }\n    else\n        return zipOpen3(pathname, append, globalcomment, NULL);\n}\n\nextern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)\n{\n    if (pzlib_filefunc_def != NULL)\n    {\n        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;\n        zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;\n        zlib_filefunc64_32_def_fill.ztell32_file = NULL;\n        zlib_filefunc64_32_def_fill.zseek32_file = NULL;\n        return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);\n    }\n    else\n        return zipOpen3(pathname, append, globalcomment, NULL);\n}\n\n\n\nextern zipFile ZEXPORT zipOpen (const char* pathname, int append)\n{\n    return zipOpen3((const void*)pathname,append,NULL,NULL);\n}\n\nextern zipFile ZEXPORT zipOpen64 (const void* pathname, int append)\n{\n    return zipOpen3(pathname,append,NULL,NULL);\n}\n\nint Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local);\nint Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local)\n{\n  /* write the local header */\n  int err;\n  uInt size_filename = (uInt)strlen(filename);\n  uInt size_extrafield = size_extrafield_local;\n\n  err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4);\n\n  if (err==ZIP_OK)\n  {\n    if(zi->ci.zip64)\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */\n    else\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */\n  }\n\n  if (err==ZIP_OK)\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2);\n\n  if (err==ZIP_OK)\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2);\n\n  if (err==ZIP_OK)\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);\n\n  // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later\n  if (err==ZIP_OK)\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */\n  if (err==ZIP_OK)\n  {\n    if(zi->ci.zip64)\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */\n    else\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */\n  }\n  if (err==ZIP_OK)\n  {\n    if(zi->ci.zip64)\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */\n    else\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */\n  }\n\n  if (err==ZIP_OK)\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2);\n\n  if(zi->ci.zip64)\n  {\n    size_extrafield += 20;\n  }\n\n  if (err==ZIP_OK)\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2);\n\n  if ((err==ZIP_OK) && (size_filename > 0))\n  {\n    if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename)\n      err = ZIP_ERRNO;\n  }\n\n  if ((err==ZIP_OK) && (size_extrafield_local > 0))\n  {\n    if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local)\n      err = ZIP_ERRNO;\n  }\n\n\n  if ((err==ZIP_OK) && (zi->ci.zip64))\n  {\n      // write the Zip64 extended info\n      short HeaderID = 1;\n      short DataSize = 16;\n      ZPOS64_T CompressedSize = 0;\n      ZPOS64_T UncompressedSize = 0;\n\n      // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file)\n      zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream);\n\n#ifndef __clang_analyzer__\n      err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2);\n      err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2);\n\n      err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8);\n      err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8);\n#endif\n  }\n\n  return err;\n}\n\n/*\n NOTE.\n When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped\n before calling this function it can be done with zipRemoveExtraInfoBlock\n\n It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize\n unnecessary allocations.\n */\nextern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,\n                                         const void* extrafield_local, uInt size_extrafield_local,\n                                         const void* extrafield_global, uInt size_extrafield_global,\n                                         const char* comment, int method, int level, int raw,\n                                         int windowBits,int memLevel, int strategy,\n                                         const char* password, uLong crcForCrypting,\n                                         uLong versionMadeBy, uLong flagBase, int zip64)\n{\n    zip64_internal* zi;\n    uInt size_filename;\n    uInt size_comment;\n    uInt i;\n    int err = ZIP_OK;\n\n#    ifdef NOCRYPT\n    if (password != NULL)\n        return ZIP_PARAMERROR;\n#    endif\n\n    if (file == NULL)\n        return ZIP_PARAMERROR;\n\n#ifdef HAVE_BZIP2\n    if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED))\n      return ZIP_PARAMERROR;\n#else\n    if ((method!=0) && (method!=Z_DEFLATED))\n      return ZIP_PARAMERROR;\n#endif\n\n    zi = (zip64_internal*)file;\n\n    if (zi->in_opened_file_inzip == 1)\n    {\n        err = zipCloseFileInZip (file);\n        if (err != ZIP_OK)\n            return err;\n    }\n\n    if (filename==NULL)\n        filename=\"-\";\n\n    if (comment==NULL)\n        size_comment = 0;\n    else\n        size_comment = (uInt)strlen(comment);\n\n    size_filename = (uInt)strlen(filename);\n\n    if (zipfi == NULL)\n        zi->ci.dosDate = 0;\n    else\n    {\n        if (zipfi->dosDate != 0)\n            zi->ci.dosDate = zipfi->dosDate;\n        else\n          zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date);\n    }\n\n    zi->ci.flag = flagBase;\n    if (level==8 || level==9)\n      zi->ci.flag |= 2;\n    if (level==2)\n      zi->ci.flag |= 4;\n    if (level==1)\n      zi->ci.flag |= 6;\n    if (password != NULL)\n      zi->ci.flag |= 1;\n\n    zi->ci.crc32 = 0;\n    zi->ci.method = method;\n    zi->ci.encrypt = 0;\n    zi->ci.stream_initialised = 0;\n    zi->ci.pos_in_buffered_data = 0;\n    zi->ci.raw = raw;\n    zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream);\n\n    zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment;\n    zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data\n\n    zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree);\n\n    zi->ci.size_centralExtra = size_extrafield_global;\n    zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);\n    /* version info */\n    zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2);\n    zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);\n    zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);\n    zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);\n    zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);\n    zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/\n    zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/\n    zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/\n    zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);\n    zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);\n    zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);\n    zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/\n\n    if (zipfi==NULL)\n        zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);\n    else\n        zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);\n\n    if (zipfi==NULL)\n        zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);\n    else\n        zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);\n\n    if(zi->ci.pos_local_header >= 0xffffffff)\n      zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4);\n    else\n      zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4);\n\n    for (i=0;i<size_filename;i++)\n        *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);\n\n    for (i=0;i<size_extrafield_global;i++)\n        *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =\n              *(((const char*)extrafield_global)+i);\n\n    for (i=0;i<size_comment;i++)\n        *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+\n              size_extrafield_global+i) = *(comment+i);\n    if (zi->ci.central_header == NULL)\n        return ZIP_INTERNALERROR;\n\n    zi->ci.zip64 = zip64;\n    zi->ci.totalCompressedData = 0;\n    zi->ci.totalUncompressedData = 0;\n    zi->ci.pos_zip64extrainfo = 0;\n\n    err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local);\n\n#ifdef HAVE_BZIP2\n    zi->ci.bstream.avail_in = (uInt)0;\n    zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;\n    zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;\n    zi->ci.bstream.total_in_hi32 = 0;\n    zi->ci.bstream.total_in_lo32 = 0;\n    zi->ci.bstream.total_out_hi32 = 0;\n    zi->ci.bstream.total_out_lo32 = 0;\n#endif\n\n    zi->ci.stream.avail_in = (uInt)0;\n    zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;\n    zi->ci.stream.next_out = zi->ci.buffered_data;\n    zi->ci.stream.total_in = 0;\n    zi->ci.stream.total_out = 0;\n    zi->ci.stream.data_type = Z_BINARY;\n\n#ifdef HAVE_BZIP2\n    if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))\n#else\n    if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))\n#endif\n    {\n        if(zi->ci.method == Z_DEFLATED)\n        {\n          zi->ci.stream.zalloc = (alloc_func)0;\n          zi->ci.stream.zfree = (free_func)0;\n          zi->ci.stream.opaque = (voidpf)0;\n\n          if (windowBits>0)\n              windowBits = -windowBits;\n\n          err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy);\n\n          if (err==Z_OK)\n              zi->ci.stream_initialised = Z_DEFLATED;\n        }\n        else if(zi->ci.method == Z_BZIP2ED)\n        {\n#ifdef HAVE_BZIP2\n            // Init BZip stuff here\n          zi->ci.bstream.bzalloc = 0;\n          zi->ci.bstream.bzfree = 0;\n          zi->ci.bstream.opaque = (voidpf)0;\n\n          err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35);\n          if(err == BZ_OK)\n            zi->ci.stream_initialised = Z_BZIP2ED;\n#endif\n        }\n\n    }\n\n#    ifndef NOCRYPT\n    zi->ci.crypt_header_size = 0;\n    if ((err==Z_OK) && (password != NULL))\n    {\n        unsigned char bufHead[RAND_HEAD_LEN];\n        unsigned int sizeHead;\n        zi->ci.encrypt = 1;\n        zi->ci.pcrc_32_tab = (const unsigned long*)get_crc_table();\n        /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/\n\n        sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);\n        zi->ci.crypt_header_size = sizeHead;\n\n        if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)\n                err = ZIP_ERRNO;\n    }\n#    endif\n\n    if (err==Z_OK)\n        zi->in_opened_file_inzip = 1;\n    return err;\n}\n\nextern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi,\n                                         const void* extrafield_local, uInt size_extrafield_local,\n                                         const void* extrafield_global, uInt size_extrafield_global,\n                                         const char* comment, int method, int level, int raw,\n                                         int windowBits,int memLevel, int strategy,\n                                         const char* password, uLong crcForCrypting,\n                                         uLong versionMadeBy, uLong flagBase)\n{\n    return zipOpenNewFileInZip4_64 (file, filename, zipfi,\n                                 extrafield_local, size_extrafield_local,\n                                 extrafield_global, size_extrafield_global,\n                                 comment, method, level, raw,\n                                 windowBits, memLevel, strategy,\n                                 password, crcForCrypting, versionMadeBy, flagBase, 0);\n}\n\nextern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi,\n                                         const void* extrafield_local, uInt size_extrafield_local,\n                                         const void* extrafield_global, uInt size_extrafield_global,\n                                         const char* comment, int method, int level, int raw,\n                                         int windowBits,int memLevel, int strategy,\n                                         const char* password, uLong crcForCrypting)\n{\n    return zipOpenNewFileInZip4_64 (file, filename, zipfi,\n                                 extrafield_local, size_extrafield_local,\n                                 extrafield_global, size_extrafield_global,\n                                 comment, method, level, raw,\n                                 windowBits, memLevel, strategy,\n                                 password, crcForCrypting, VERSIONMADEBY, 0, 0);\n}\n\nextern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,\n                                         const void* extrafield_local, uInt size_extrafield_local,\n                                         const void* extrafield_global, uInt size_extrafield_global,\n                                         const char* comment, int method, int level, int raw,\n                                         int windowBits,int memLevel, int strategy,\n                                         const char* password, uLong crcForCrypting, int zip64)\n{\n    return zipOpenNewFileInZip4_64 (file, filename, zipfi,\n                                 extrafield_local, size_extrafield_local,\n                                 extrafield_global, size_extrafield_global,\n                                 comment, method, level, raw,\n                                 windowBits, memLevel, strategy,\n                                 password, crcForCrypting, VERSIONMADEBY, 0, zip64);\n}\n\nextern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi,\n                                        const void* extrafield_local, uInt size_extrafield_local,\n                                        const void* extrafield_global, uInt size_extrafield_global,\n                                        const char* comment, int method, int level, int raw)\n{\n    return zipOpenNewFileInZip4_64 (file, filename, zipfi,\n                                 extrafield_local, size_extrafield_local,\n                                 extrafield_global, size_extrafield_global,\n                                 comment, method, level, raw,\n                                 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,\n                                 NULL, 0, VERSIONMADEBY, 0, 0);\n}\n\nextern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,\n                                        const void* extrafield_local, uInt size_extrafield_local,\n                                        const void* extrafield_global, uInt size_extrafield_global,\n                                        const char* comment, int method, int level, int raw, int zip64)\n{\n    return zipOpenNewFileInZip4_64 (file, filename, zipfi,\n                                 extrafield_local, size_extrafield_local,\n                                 extrafield_global, size_extrafield_global,\n                                 comment, method, level, raw,\n                                 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,\n                                 NULL, 0, VERSIONMADEBY, 0, zip64);\n}\n\nextern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,\n                                        const void* extrafield_local, uInt size_extrafield_local,\n                                        const void*extrafield_global, uInt size_extrafield_global,\n                                        const char* comment, int method, int level, int zip64)\n{\n    return zipOpenNewFileInZip4_64 (file, filename, zipfi,\n                                 extrafield_local, size_extrafield_local,\n                                 extrafield_global, size_extrafield_global,\n                                 comment, method, level, 0,\n                                 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,\n                                 NULL, 0, VERSIONMADEBY, 0, zip64);\n}\n\nextern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi,\n                                        const void* extrafield_local, uInt size_extrafield_local,\n                                        const void*extrafield_global, uInt size_extrafield_global,\n                                        const char* comment, int method, int level)\n{\n    return zipOpenNewFileInZip4_64 (file, filename, zipfi,\n                                 extrafield_local, size_extrafield_local,\n                                 extrafield_global, size_extrafield_global,\n                                 comment, method, level, 0,\n                                 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,\n                                 NULL, 0, VERSIONMADEBY, 0, 0);\n}\n\nlocal int zip64FlushWriteBuffer(zip64_internal* zi)\n{\n    int err=ZIP_OK;\n\n    if (zi->ci.encrypt != 0)\n    {\n#ifndef NOCRYPT\n        uInt i;\n        int t;\n        for (i=0;i<zi->ci.pos_in_buffered_data;i++)\n            zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t);\n#endif\n    }\n\n    if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data)\n      err = ZIP_ERRNO;\n\n    zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data;\n\n#ifdef HAVE_BZIP2\n    if(zi->ci.method == Z_BZIP2ED)\n    {\n      zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32;\n      zi->ci.bstream.total_in_lo32 = 0;\n      zi->ci.bstream.total_in_hi32 = 0;\n    }\n    else\n#endif\n    {\n      zi->ci.totalUncompressedData += zi->ci.stream.total_in;\n      zi->ci.stream.total_in = 0;\n    }\n\n\n    zi->ci.pos_in_buffered_data = 0;\n\n    return err;\n}\n\nextern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len)\n{\n    zip64_internal* zi;\n    int err=ZIP_OK;\n\n    if (file == NULL)\n        return ZIP_PARAMERROR;\n    zi = (zip64_internal*)file;\n\n    if (zi->in_opened_file_inzip == 0)\n        return ZIP_PARAMERROR;\n\n    zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len);\n\n#ifdef HAVE_BZIP2\n    if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw))\n    {\n      zi->ci.bstream.next_in = (void*)buf;\n      zi->ci.bstream.avail_in = len;\n      err = BZ_RUN_OK;\n\n      while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0))\n      {\n        if (zi->ci.bstream.avail_out == 0)\n        {\n          if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)\n            err = ZIP_ERRNO;\n          zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;\n          zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;\n        }\n\n\n        if(err != BZ_RUN_OK)\n          break;\n\n        if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))\n        {\n          uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32;\n//          uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32;\n          err=BZ2_bzCompress(&zi->ci.bstream,  BZ_RUN);\n\n          zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ;\n        }\n      }\n\n      if(err == BZ_RUN_OK)\n        err = ZIP_OK;\n    }\n    else\n#endif\n    {\n      zi->ci.stream.next_in = (Bytef*)buf;\n      zi->ci.stream.avail_in = len;\n\n      while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))\n      {\n          if (zi->ci.stream.avail_out == 0)\n          {\n              if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)\n                  err = ZIP_ERRNO;\n              zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;\n              zi->ci.stream.next_out = zi->ci.buffered_data;\n          }\n\n\n          if(err != ZIP_OK)\n              break;\n\n          if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))\n          {\n              uLong uTotalOutBefore = zi->ci.stream.total_out;\n              err=deflate(&zi->ci.stream,  Z_NO_FLUSH);\n              if(uTotalOutBefore > zi->ci.stream.total_out)\n              {\n                int bBreak = 0;\n                bBreak++;\n              }\n\n              zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;\n          }\n          else\n          {\n              uInt copy_this,i;\n              if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)\n                  copy_this = zi->ci.stream.avail_in;\n              else\n                  copy_this = zi->ci.stream.avail_out;\n\n              for (i = 0; i < copy_this; i++)\n                  *(((char*)zi->ci.stream.next_out)+i) =\n                      *(((const char*)zi->ci.stream.next_in)+i);\n              {\n                  zi->ci.stream.avail_in -= copy_this;\n                  zi->ci.stream.avail_out-= copy_this;\n                  zi->ci.stream.next_in+= copy_this;\n                  zi->ci.stream.next_out+= copy_this;\n                  zi->ci.stream.total_in+= copy_this;\n                  zi->ci.stream.total_out+= copy_this;\n                  zi->ci.pos_in_buffered_data += copy_this;\n              }\n          }\n      }// while(...)\n    }\n\n    return err;\n}\n\nextern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32)\n{\n    return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32);\n}\n\nextern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32)\n{\n    zip64_internal* zi;\n    ZPOS64_T compressed_size;\n    uLong invalidValue = 0xffffffff;\n    short datasize = 0;\n    int err=ZIP_OK;\n\n    if (file == NULL)\n        return ZIP_PARAMERROR;\n    zi = (zip64_internal*)file;\n\n    if (zi->in_opened_file_inzip == 0)\n        return ZIP_PARAMERROR;\n    zi->ci.stream.avail_in = 0;\n\n    if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))\n                {\n                        while (err==ZIP_OK)\n                        {\n                                uLong uTotalOutBefore;\n                                if (zi->ci.stream.avail_out == 0)\n                                {\n                                        if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)\n\t\t\t\t\t\t\t\t\t\t{\n#ifndef __clang_analyzer__\n                                                err = ZIP_ERRNO;\n#endif\n\t\t\t\t\t\t\t\t\t\t}\n                                        zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;\n#ifndef __clang_analyzer__\n                                        zi->ci.stream.next_out = zi->ci.buffered_data;\n#endif\n                                }\n                                uTotalOutBefore = zi->ci.stream.total_out;\n                                err=deflate(&zi->ci.stream,  Z_FINISH);\n                                zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;\n                        }\n                }\n    else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))\n    {\n#ifdef HAVE_BZIP2\n      err = BZ_FINISH_OK;\n      while (err==BZ_FINISH_OK)\n      {\n        uLong uTotalOutBefore;\n        if (zi->ci.bstream.avail_out == 0)\n        {\n          if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)\n            err = ZIP_ERRNO;\n          zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;\n          zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;\n        }\n        uTotalOutBefore = zi->ci.bstream.total_out_lo32;\n        err=BZ2_bzCompress(&zi->ci.bstream,  BZ_FINISH);\n        if(err == BZ_STREAM_END)\n          err = Z_STREAM_END;\n\n        zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore);\n      }\n\n      if(err == BZ_FINISH_OK)\n        err = ZIP_OK;\n#endif\n    }\n\n    if (err==Z_STREAM_END)\n        err=ZIP_OK; /* this is normal */\n\n    if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))\n                {\n        if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO)\n            err = ZIP_ERRNO;\n                }\n\n    if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))\n    {\n        int tmp_err = deflateEnd(&zi->ci.stream);\n        if (err == ZIP_OK)\n            err = tmp_err;\n        zi->ci.stream_initialised = 0;\n    }\n#ifdef HAVE_BZIP2\n    else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))\n    {\n      int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream);\n                        if (err==ZIP_OK)\n                                err = tmperr;\n                        zi->ci.stream_initialised = 0;\n    }\n#endif\n\n    if (!zi->ci.raw)\n    {\n        crc32 = (uLong)zi->ci.crc32;\n        uncompressed_size = zi->ci.totalUncompressedData;\n    }\n    compressed_size = zi->ci.totalCompressedData;\n\n#    ifndef NOCRYPT\n    compressed_size += zi->ci.crypt_header_size;\n#    endif\n\n    // update Current Item crc and sizes,\n    if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff)\n    {\n      /*version Made by*/\n      zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2);\n      /*version needed*/\n      zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2);\n\n    }\n\n    zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/\n\n\n    if(compressed_size >= 0xffffffff)\n      zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/\n    else\n      zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/\n\n    /// set internal file attributes field\n    if (zi->ci.stream.data_type == Z_ASCII)\n        zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);\n\n    if(uncompressed_size >= 0xffffffff)\n      zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/\n    else\n      zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/\n\n    // Add ZIP64 extra info field for uncompressed size\n    if(uncompressed_size >= 0xffffffff)\n      datasize += 8;\n\n    // Add ZIP64 extra info field for compressed size\n    if(compressed_size >= 0xffffffff)\n      datasize += 8;\n\n    // Add ZIP64 extra info field for relative offset to local file header of current file\n    if(zi->ci.pos_local_header >= 0xffffffff)\n      datasize += 8;\n\n    if(datasize > 0)\n    {\n      char* p = NULL;\n\n      if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree)\n      {\n        // we can not write more data to the buffer that we have room for.\n        return ZIP_BADZIPFILE;\n      }\n\n      p = zi->ci.central_header + zi->ci.size_centralheader;\n\n      // Add Extra Information Header for 'ZIP64 information'\n      zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID\n      p += 2;\n      zip64local_putValue_inmemory(p, datasize, 2); // DataSize\n      p += 2;\n\n      if(uncompressed_size >= 0xffffffff)\n      {\n        zip64local_putValue_inmemory(p, uncompressed_size, 8);\n        p += 8;\n      }\n\n      if(compressed_size >= 0xffffffff)\n      {\n        zip64local_putValue_inmemory(p, compressed_size, 8);\n        p += 8;\n      }\n\n      if(zi->ci.pos_local_header >= 0xffffffff)\n      {\n        zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8);\n#ifndef __clang_analyzer__\n        p += 8;\n#endif\n      }\n\n      // Update how much extra free space we got in the memory buffer\n      // and increase the centralheader size so the new ZIP64 fields are included\n      // ( 4 below is the size of HeaderID and DataSize field )\n      zi->ci.size_centralExtraFree -= datasize + 4;\n      zi->ci.size_centralheader += datasize + 4;\n\n      // Update the extra info size field\n      zi->ci.size_centralExtra += datasize + 4;\n      zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2);\n    }\n\n    if (err==ZIP_OK)\n        err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader);\n\n    free(zi->ci.central_header);\n\n    if (err==ZIP_OK)\n    {\n        // Update the LocalFileHeader with the new values.\n\n        ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);\n\n        if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)\n            err = ZIP_ERRNO;\n\n        if (err==ZIP_OK)\n            err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */\n\n        if(uncompressed_size >= 0xffffffff)\n        {\n          if(zi->ci.pos_zip64extrainfo > 0)\n          {\n            // Update the size in the ZIP64 extended field.\n            if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0)\n              err = ZIP_ERRNO;\n\n            if (err==ZIP_OK) /* compressed size, unknown */\n              err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8);\n\n            if (err==ZIP_OK) /* uncompressed size, unknown */\n              err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8);\n          }\n        }\n        else\n        {\n          if (err==ZIP_OK) /* compressed size, unknown */\n              err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);\n\n          if (err==ZIP_OK) /* uncompressed size, unknown */\n              err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);\n        }\n\n        if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)\n            err = ZIP_ERRNO;\n    }\n\n    zi->number_entry ++;\n    zi->in_opened_file_inzip = 0;\n\n    return err;\n}\n\nextern int ZEXPORT zipCloseFileInZip (zipFile file)\n{\n    return zipCloseFileInZipRaw (file,0,0);\n}\n\nint Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip);\nint Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip)\n{\n  int err = ZIP_OK;\n  ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset;\n\n  err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4);\n\n  /*num disks*/\n    if (err==ZIP_OK) /* number of the disk with the start of the central directory */\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);\n\n  /*relative offset*/\n    if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8);\n\n  /*total disks*/ /* Do not support spawning of disk so always say 1 here*/\n    if (err==ZIP_OK) /* number of the disk with the start of the central directory */\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4);\n\n    return err;\n}\n\nint Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip);\nint Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)\n{\n  int err = ZIP_OK;\n\n  uLong Zip64DataSize = 44;\n\n  err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4);\n\n  if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ?\n\n  if (err==ZIP_OK) /* version made by */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);\n\n  if (err==ZIP_OK) /* version needed */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);\n\n  if (err==ZIP_OK) /* number of this disk */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);\n\n  if (err==ZIP_OK) /* number of the disk with the start of the central directory */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);\n\n  if (err==ZIP_OK) /* total number of entries in the central dir on this disk */\n    err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);\n\n  if (err==ZIP_OK) /* total number of entries in the central dir */\n    err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);\n\n  if (err==ZIP_OK) /* size of the central directory */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8);\n\n  if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */\n  {\n    ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8);\n  }\n  return err;\n}\n\nint Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip);\nint Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)\n{\n  int err = ZIP_OK;\n\n  /*signature*/\n  err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);\n\n  if (err==ZIP_OK) /* number of this disk */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);\n\n  if (err==ZIP_OK) /* number of the disk with the start of the central directory */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);\n\n  if (err==ZIP_OK) /* total number of entries in the central dir on this disk */\n  {\n    {\n      if(zi->number_entry >= 0xFFFF)\n        err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record\n      else\n        err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);\n    }\n  }\n\n  if (err==ZIP_OK) /* total number of entries in the central dir */\n  {\n    if(zi->number_entry >= 0xFFFF)\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record\n    else\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);\n  }\n\n  if (err==ZIP_OK) /* size of the central directory */\n    err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4);\n\n  if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */\n  {\n    ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;\n    if(pos >= 0xffffffff)\n    {\n      err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4);\n    }\n    else\n                  err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);\n  }\n\n   return err;\n}\n\nint Write_GlobalComment(zip64_internal* zi, const char* global_comment);\nint Write_GlobalComment(zip64_internal* zi, const char* global_comment)\n{\n  int err = ZIP_OK;\n  uInt size_global_comment = 0;\n\n  if(global_comment != NULL)\n    size_global_comment = (uInt)strlen(global_comment);\n\n  err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);\n\n  if (err == ZIP_OK && size_global_comment > 0)\n  {\n    if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment)\n      err = ZIP_ERRNO;\n  }\n  return err;\n}\n\nextern int ZEXPORT zipClose (zipFile file, const char* global_comment)\n{\n    zip64_internal* zi;\n    int err = 0;\n    uLong size_centraldir = 0;\n    ZPOS64_T centraldir_pos_inzip;\n    ZPOS64_T pos;\n\n    if (file == NULL)\n        return ZIP_PARAMERROR;\n\n    zi = (zip64_internal*)file;\n\n    if (zi->in_opened_file_inzip == 1)\n    {\n        err = zipCloseFileInZip (file);\n    }\n\n#ifndef NO_ADDFILEINEXISTINGZIP\n    if (global_comment==NULL)\n        global_comment = zi->globalcomment;\n#endif\n\n    centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);\n\n    if (err==ZIP_OK)\n    {\n        linkedlist_datablock_internal* ldi = zi->central_dir.first_block;\n        while (ldi!=NULL)\n        {\n            if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))\n            {\n                if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block)\n                    err = ZIP_ERRNO;\n            }\n\n            size_centraldir += ldi->filled_in_this_block;\n            ldi = ldi->next_datablock;\n        }\n    }\n    free_linkedlist(&(zi->central_dir));\n\n    pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;\n    if(pos >= 0xffffffff)\n    {\n      ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream);\n      Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);\n\n      Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos);\n    }\n\n    if (err==ZIP_OK)\n      err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);\n\n    if(err == ZIP_OK)\n      err = Write_GlobalComment(zi, global_comment);\n\n    if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0)\n        if (err == ZIP_OK)\n            err = ZIP_ERRNO;\n\n#ifndef NO_ADDFILEINEXISTINGZIP\n    TRYFREE(zi->globalcomment);\n#endif\n    TRYFREE(zi);\n\n    return err;\n}\n\nextern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader)\n{\n  char* p = pData;\n  int size = 0;\n  char* pNewHeader;\n  char* pTmp;\n  short header;\n  short dataSize;\n\n  int retVal = ZIP_OK;\n\n  if(pData == NULL || *dataLen < 4)\n    return ZIP_PARAMERROR;\n\n  pNewHeader = (char*)ALLOC(*dataLen);\n  pTmp = pNewHeader;\n\n  while(p < (pData + *dataLen))\n  {\n    header = *(short*)p;\n    dataSize = *(((short*)p)+1);\n\n    if( header == sHeader ) // Header found.\n    {\n      p += dataSize + 4; // skip it. do not copy to temp buffer\n    }\n    else\n    {\n      // Extra Info block should not be removed, So copy it to the temp buffer.\n      memcpy(pTmp, p, dataSize + 4);\n      p += dataSize + 4;\n      size += dataSize + 4;\n    }\n\n  }\n\n  if(size < *dataLen)\n  {\n    // clean old extra info block.\n    memset(pData,0, *dataLen);\n\n    // copy the new extra info block over the old\n    if(size > 0)\n      memcpy(pData, pNewHeader, size);\n\n    // set the new extra info size\n    *dataLen = size;\n\n    retVal = ZIP_OK;\n  }\n  else\n    retVal = ZIP_ERRNO;\n\n  TRYFREE(pNewHeader);\n\n  return retVal;\n}\n"
  },
  {
    "path": "Revolved/minizip/zip.h",
    "content": "/* zip.h -- IO on .zip files using zlib\n   Version 1.1, February 14h, 2010\n   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )\n\n         Modifications for Zip64 support\n         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )\n\n         For more info read MiniZip_info.txt\n\n         ---------------------------------------------------------------------------\n\n   Condition of use and distribution are the same than zlib :\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n        ---------------------------------------------------------------------------\n\n        Changes\n\n        See header of zip.h\n\n*/\n\n#ifndef _zip12_H\n#define _zip12_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//#define HAVE_BZIP2\n\n#ifndef _ZLIB_H\n#include \"zlib.h\"\n#endif\n\n#ifndef _ZLIBIOAPI_H\n#include \"ioapi.h\"\n#endif\n\n#ifdef HAVE_BZIP2\n#include \"bzlib.h\"\n#endif\n\n#define Z_BZIP2ED 12\n\n#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)\n/* like the STRICT of WIN32, we define a pointer that cannot be converted\n    from (void*) without cast */\ntypedef struct TagzipFile__ { int unused; } zipFile__;\ntypedef zipFile__ *zipFile;\n#else\ntypedef voidp zipFile;\n#endif\n\n#define ZIP_OK                          (0)\n#define ZIP_EOF                         (0)\n#define ZIP_ERRNO                       (Z_ERRNO)\n#define ZIP_PARAMERROR                  (-102)\n#define ZIP_BADZIPFILE                  (-103)\n#define ZIP_INTERNALERROR               (-104)\n\n#ifndef DEF_MEM_LEVEL\n#  if MAX_MEM_LEVEL >= 8\n#    define DEF_MEM_LEVEL 8\n#  else\n#    define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#  endif\n#endif\n/* default memLevel */\n\n/* tm_zip contain date/time info */\ntypedef struct tm_zip_s\n{\n    uInt tm_sec;            /* seconds after the minute - [0,59] */\n    uInt tm_min;            /* minutes after the hour - [0,59] */\n    uInt tm_hour;           /* hours since midnight - [0,23] */\n    uInt tm_mday;           /* day of the month - [1,31] */\n    uInt tm_mon;            /* months since January - [0,11] */\n    uInt tm_year;           /* years - [1980..2044] */\n} tm_zip;\n\ntypedef struct\n{\n    tm_zip      tmz_date;       /* date in understandable format           */\n    uLong       dosDate;       /* if dos_date == 0, tmu_date is used      */\n/*    uLong       flag;        */   /* general purpose bit flag        2 bytes */\n\n    uLong       internal_fa;    /* internal file attributes        2 bytes */\n    uLong       external_fa;    /* external file attributes        4 bytes */\n} zip_fileinfo;\n\ntypedef const char* zipcharpc;\n\n\n#define APPEND_STATUS_CREATE        (0)\n#define APPEND_STATUS_CREATEAFTER   (1)\n#define APPEND_STATUS_ADDINZIP      (2)\n\nextern zipFile ZEXPORT zipOpen OF((const char *pathname, int append));\nextern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append));\n/*\n  Create a zipfile.\n     pathname contain on Windows XP a filename like \"c:\\\\zlib\\\\zlib113.zip\" or on\n       an Unix computer \"zlib/zlib113.zip\".\n     if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip\n       will be created at the end of the file.\n         (useful if the file contain a self extractor code)\n     if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will\n       add files in existing zip (be sure you don't add file that doesn't exist)\n     If the zipfile cannot be opened, the return value is NULL.\n     Else, the return value is a zipFile Handle, usable with other function\n       of this zip package.\n*/\n\n/* Note : there is no delete function into a zipfile.\n   If you want delete file into a zipfile, you must open a zipfile, and create another\n   Of couse, you can use RAW reading and writing to copy the file you did not want delte\n*/\n\nextern zipFile ZEXPORT zipOpen2 OF((const char *pathname,\n                                   int append,\n                                   zipcharpc* globalcomment,\n                                   zlib_filefunc_def* pzlib_filefunc_def));\n\nextern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname,\n                                   int append,\n                                   zipcharpc* globalcomment,\n                                   zlib_filefunc64_def* pzlib_filefunc_def));\n\nextern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,\n                       const char* filename,\n                       const zip_fileinfo* zipfi,\n                       const void* extrafield_local,\n                       uInt size_extrafield_local,\n                       const void* extrafield_global,\n                       uInt size_extrafield_global,\n                       const char* comment,\n                       int method,\n                       int level));\n\nextern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file,\n                       const char* filename,\n                       const zip_fileinfo* zipfi,\n                       const void* extrafield_local,\n                       uInt size_extrafield_local,\n                       const void* extrafield_global,\n                       uInt size_extrafield_global,\n                       const char* comment,\n                       int method,\n                       int level,\n                       int zip64));\n\n/*\n  Open a file in the ZIP for writing.\n  filename : the filename in zip (if NULL, '-' without quote will be used\n  *zipfi contain supplemental information\n  if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local\n    contains the extrafield data the the local header\n  if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global\n    contains the extrafield data the the local header\n  if comment != NULL, comment contain the comment string\n  method contain the compression method (0 for store, Z_DEFLATED for deflate)\n  level contain the level of compression (can be Z_DEFAULT_COMPRESSION)\n  zip64 is set to 1 if a zip64 extended information block should be added to the local file header.\n                    this MUST be '1' if the uncompressed size is >= 0xffffffff.\n\n*/\n\n\nextern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file,\n                                            const char* filename,\n                                            const zip_fileinfo* zipfi,\n                                            const void* extrafield_local,\n                                            uInt size_extrafield_local,\n                                            const void* extrafield_global,\n                                            uInt size_extrafield_global,\n                                            const char* comment,\n                                            int method,\n                                            int level,\n                                            int raw));\n\n\nextern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file,\n                                            const char* filename,\n                                            const zip_fileinfo* zipfi,\n                                            const void* extrafield_local,\n                                            uInt size_extrafield_local,\n                                            const void* extrafield_global,\n                                            uInt size_extrafield_global,\n                                            const char* comment,\n                                            int method,\n                                            int level,\n                                            int raw,\n                                            int zip64));\n/*\n  Same than zipOpenNewFileInZip, except if raw=1, we write raw file\n */\n\nextern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,\n                                            const char* filename,\n                                            const zip_fileinfo* zipfi,\n                                            const void* extrafield_local,\n                                            uInt size_extrafield_local,\n                                            const void* extrafield_global,\n                                            uInt size_extrafield_global,\n                                            const char* comment,\n                                            int method,\n                                            int level,\n                                            int raw,\n                                            int windowBits,\n                                            int memLevel,\n                                            int strategy,\n                                            const char* password,\n                                            uLong crcForCrypting));\n\nextern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file,\n                                            const char* filename,\n                                            const zip_fileinfo* zipfi,\n                                            const void* extrafield_local,\n                                            uInt size_extrafield_local,\n                                            const void* extrafield_global,\n                                            uInt size_extrafield_global,\n                                            const char* comment,\n                                            int method,\n                                            int level,\n                                            int raw,\n                                            int windowBits,\n                                            int memLevel,\n                                            int strategy,\n                                            const char* password,\n                                            uLong crcForCrypting,\n                                            int zip64\n                                            ));\n\n/*\n  Same than zipOpenNewFileInZip2, except\n    windowBits,memLevel,,strategy : see parameter strategy in deflateInit2\n    password : crypting password (NULL for no crypting)\n    crcForCrypting : crc of file to compress (needed for crypting)\n */\n\nextern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file,\n                                            const char* filename,\n                                            const zip_fileinfo* zipfi,\n                                            const void* extrafield_local,\n                                            uInt size_extrafield_local,\n                                            const void* extrafield_global,\n                                            uInt size_extrafield_global,\n                                            const char* comment,\n                                            int method,\n                                            int level,\n                                            int raw,\n                                            int windowBits,\n                                            int memLevel,\n                                            int strategy,\n                                            const char* password,\n                                            uLong crcForCrypting,\n                                            uLong versionMadeBy,\n                                            uLong flagBase\n                                            ));\n\n\nextern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file,\n                                            const char* filename,\n                                            const zip_fileinfo* zipfi,\n                                            const void* extrafield_local,\n                                            uInt size_extrafield_local,\n                                            const void* extrafield_global,\n                                            uInt size_extrafield_global,\n                                            const char* comment,\n                                            int method,\n                                            int level,\n                                            int raw,\n                                            int windowBits,\n                                            int memLevel,\n                                            int strategy,\n                                            const char* password,\n                                            uLong crcForCrypting,\n                                            uLong versionMadeBy,\n                                            uLong flagBase,\n                                            int zip64\n                                            ));\n/*\n  Same than zipOpenNewFileInZip4, except\n    versionMadeBy : value for Version made by field\n    flag : value for flag field (compression level info will be added)\n */\n\n\nextern int ZEXPORT zipWriteInFileInZip OF((zipFile file,\n                       const void* buf,\n                       unsigned len));\n/*\n  Write data in the zipfile\n*/\n\nextern int ZEXPORT zipCloseFileInZip OF((zipFile file));\n/*\n  Close the current file in the zipfile\n*/\n\nextern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,\n                                            uLong uncompressed_size,\n                                            uLong crc32));\n\nextern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file,\n                                            ZPOS64_T uncompressed_size,\n                                            uLong crc32));\n\n/*\n  Close the current file in the zipfile, for file opened with\n    parameter raw=1 in zipOpenNewFileInZip2\n  uncompressed_size and crc32 are value for the uncompressed size\n*/\n\nextern int ZEXPORT zipClose OF((zipFile file,\n                const char* global_comment));\n/*\n  Close the zipfile\n*/\n\n\nextern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader));\n/*\n  zipRemoveExtraInfoBlock -  Added by Mathias Svensson\n\n  Remove extra information block from a extra information data for the local file header or central directory header\n\n  It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.\n\n  0x0001 is the signature header for the ZIP64 extra information blocks\n\n  usage.\n                        Remove ZIP64 Extra information from a central director extra field data\n              zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001);\n\n                        Remove ZIP64 Extra information from a Local File Header extra field data\n        zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);\n*/\n\t\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _zip64_H */\n"
  },
  {
    "path": "Revolved/model1.rvlvd",
    "content": "{\"major\":1,\"model\":{\"segments\":[{\"colorIndex\":3,\"endPoints\":[{\"x\":0,\"y\":1.304688},{\"x\":0.1979167,\"y\":1.114583}],\"controlPoints\":[{\"x\":0.04774304,\"y\":1.3125,\"snapped\":false},{\"x\":0.2022569,\"y\":1.239583,\"snapped\":false}]},{\"colorIndex\":2,\"endPoints\":[{\"x\":0.1979167,\"y\":1.114583},{\"x\":0.4505208,\"y\":0.9557292}],\"controlPoints\":[{\"x\":0.3133681,\"y\":1.212674,\"snapped\":false},{\"x\":0.5173612,\"y\":1.112847,\"snapped\":false}]},{\"colorIndex\":1,\"endPoints\":[{\"x\":0.4505208,\"y\":0.9557292},{\"x\":0.7109375,\"y\":0.734375}],\"controlPoints\":[{\"x\":0.5972223,\"y\":1.027778,\"snapped\":false},{\"x\":0.7621527,\"y\":0.8550348,\"snapped\":false}]},{\"colorIndex\":0,\"endPoints\":[{\"x\":0.7109375,\"y\":0.734375},{\"x\":0.9322917,\"y\":0.4661458}],\"controlPoints\":[{\"x\":0.8784722,\"y\":0.7855903,\"snapped\":false},{\"x\":1.022569,\"y\":0.5842014,\"snapped\":false}]},{\"colorIndex\":11,\"endPoints\":[{\"x\":0.9322917,\"y\":0.4661458},{\"x\":1.080729,\"y\":0.1927083}],\"controlPoints\":[{\"x\":1.109375,\"y\":0.5104167,\"snapped\":false},{\"x\":1.210938,\"y\":0.2864584,\"snapped\":false}]},{\"colorIndex\":10,\"endPoints\":[{\"x\":1.080729,\"y\":0.1927083},{\"x\":1.166667,\"y\":-0.140625}],\"controlPoints\":[{\"x\":1.286458,\"y\":0.1779514,\"snapped\":false},{\"x\":1.325521,\"y\":-0.06597223,\"snapped\":false}]},{\"colorIndex\":9,\"endPoints\":[{\"x\":1.166667,\"y\":-0.140625},{\"x\":1.221354,\"y\":-0.5078125}],\"controlPoints\":[{\"x\":1.382812,\"y\":-0.1848958,\"snapped\":false},{\"x\":1.393229,\"y\":-0.4661459,\"snapped\":false}]},{\"colorIndex\":8,\"endPoints\":[{\"x\":1.221354,\"y\":-0.5078125},{\"x\":1.179688,\"y\":-0.8828125}],\"controlPoints\":[{\"x\":1.366319,\"y\":-0.546875,\"snapped\":false},{\"x\":1.352431,\"y\":-0.8880209,\"snapped\":false}]},{\"colorIndex\":7,\"endPoints\":[{\"x\":1.179688,\"y\":-0.8828125},{\"x\":1.057292,\"y\":-1.177083}],\"controlPoints\":[{\"x\":1.295139,\"y\":-0.9704861,\"snapped\":false},{\"x\":1.22309,\"y\":-1.21441,\"snapped\":false}]},{\"colorIndex\":6,\"endPoints\":[{\"x\":1.057292,\"y\":-1.177083},{\"x\":0.8541667,\"y\":-1.421875}],\"controlPoints\":[{\"x\":1.169271,\"y\":-1.284722,\"snapped\":false},{\"x\":1.013021,\"y\":-1.493924,\"snapped\":false}]},{\"colorIndex\":5,\"endPoints\":[{\"x\":0.8541667,\"y\":-1.421875},{\"x\":0.4661458,\"y\":-1.632812}],\"controlPoints\":[{\"x\":0.8524306,\"y\":-1.640625,\"snapped\":false},{\"x\":0.6059028,\"y\":-1.757812,\"snapped\":false}]},{\"colorIndex\":4,\"endPoints\":[{\"x\":0.4661458,\"y\":-1.632812},{\"x\":0,\"y\":-1.710938}],\"controlPoints\":[{\"x\":0.3003472,\"y\":-1.756944,\"snapped\":false},{\"x\":0.1553819,\"y\":-1.684896,\"snapped\":true}]}],\"connections\":[{\"to\":{\"index\":1,\"end\":1},\"from\":{\"index\":2,\"end\":0}},{\"to\":{\"index\":9,\"end\":1},\"from\":{\"index\":10,\"end\":0}},{\"to\":{\"index\":8,\"end\":1},\"from\":{\"index\":9,\"end\":0}},{\"to\":{\"index\":10,\"end\":1},\"from\":{\"index\":11,\"end\":0}},{\"to\":{\"index\":2,\"end\":1},\"from\":{\"index\":3,\"end\":0}},{\"to\":{\"index\":3,\"end\":1},\"from\":{\"index\":4,\"end\":0}},{\"to\":{\"index\":0,\"end\":1},\"from\":{\"index\":1,\"end\":0}},{\"to\":{\"index\":7,\"end\":1},\"from\":{\"index\":8,\"end\":0}},{\"to\":{\"index\":4,\"end\":1},\"from\":{\"index\":5,\"end\":0}},{\"to\":{\"index\":6,\"end\":1},\"from\":{\"index\":7,\"end\":0}},{\"to\":{\"index\":5,\"end\":1},\"from\":{\"index\":6,\"end\":0}}]},\"minor\":0}"
  },
  {
    "path": "Revolved/model2.rvlvd",
    "content": "{\"major\":1,\"model\":{\"segments\":[{\"colorIndex\":9,\"endPoints\":[{\"x\":1.486979,\"y\":-1.179688},{\"x\":1.658854,\"y\":-0.9322917}],\"controlPoints\":[{\"x\":1.716141,\"y\":-1.180089,\"snapped\":false},{\"x\":1.666667,\"y\":-1.018229,\"snapped\":false}]},{\"colorIndex\":9,\"endPoints\":[{\"x\":1.619792,\"y\":-0.6119792},{\"x\":1.570312,\"y\":-0.3229167}],\"controlPoints\":[{\"x\":1.603299,\"y\":-0.515625,\"snapped\":true},{\"x\":1.586805,\"y\":-0.4192708,\"snapped\":true}]},{\"colorIndex\":9,\"endPoints\":[{\"x\":1.393229,\"y\":0.4166667},{\"x\":1.28125,\"y\":0.671875}],\"controlPoints\":[{\"x\":1.355903,\"y\":0.5017361,\"snapped\":true},{\"x\":1.318576,\"y\":0.5868056,\"snapped\":true}]},{\"colorIndex\":9,\"endPoints\":[{\"x\":1.53125,\"y\":-0.04947917},{\"x\":1.455729,\"y\":0.1770833}],\"controlPoints\":[{\"x\":1.506076,\"y\":0.02604166,\"snapped\":true},{\"x\":1.480903,\"y\":0.1015625,\"snapped\":true}]},{\"colorIndex\":9,\"endPoints\":[{\"x\":1.117188,\"y\":0.8984375},{\"x\":0.9505209,\"y\":1.083333}],\"controlPoints\":[{\"x\":1.061632,\"y\":0.9600694,\"snapped\":true},{\"x\":1.006077,\"y\":1.021701,\"snapped\":true}]},{\"colorIndex\":9,\"endPoints\":[{\"x\":0.7265625,\"y\":1.221354},{\"x\":0.4557292,\"y\":1.260417}],\"controlPoints\":[{\"x\":0.6362847,\"y\":1.234375,\"snapped\":true},{\"x\":0.5460069,\"y\":1.247396,\"snapped\":true}]},{\"colorIndex\":9,\"endPoints\":[{\"x\":0,\"y\":1.309896},{\"x\":0.15625,\"y\":1.291667}],\"controlPoints\":[{\"x\":0.05208334,\"y\":1.30382,\"snapped\":true},{\"x\":0.1041667,\"y\":1.297743,\"snapped\":true}]},{\"colorIndex\":3,\"endPoints\":[{\"x\":0.15625,\"y\":1.291667},{\"x\":0.4557292,\"y\":1.260417}],\"controlPoints\":[{\"x\":0.1493055,\"y\":1.044271,\"snapped\":false},{\"x\":0.4366319,\"y\":1.049479,\"snapped\":false}]},{\"colorIndex\":3,\"endPoints\":[{\"x\":0.7265625,\"y\":1.221354},{\"x\":0.9505209,\"y\":1.083333}],\"controlPoints\":[{\"x\":0.6501737,\"y\":1.055555,\"snapped\":false},{\"x\":0.7456598,\"y\":0.9079859,\"snapped\":false}]},{\"colorIndex\":3,\"endPoints\":[{\"x\":1.28125,\"y\":0.671875},{\"x\":1.117188,\"y\":0.8984375}],\"controlPoints\":[{\"x\":1.026041,\"y\":0.5442708,\"snapped\":false},{\"x\":0.9401042,\"y\":0.7395834,\"snapped\":false}]},{\"colorIndex\":3,\"endPoints\":[{\"x\":1.455729,\"y\":0.1770833},{\"x\":1.393229,\"y\":0.4166667}],\"controlPoints\":[{\"x\":1.1875,\"y\":0.07291667,\"snapped\":false},{\"x\":1.130208,\"y\":0.3671875,\"snapped\":false}]},{\"colorIndex\":3,\"endPoints\":[{\"x\":1.570312,\"y\":-0.3229167},{\"x\":1.53125,\"y\":-0.04947917}],\"controlPoints\":[{\"x\":1.34375,\"y\":-0.4166667,\"snapped\":false},{\"x\":1.260417,\"y\":-0.0859375,\"snapped\":false}]},{\"colorIndex\":3,\"endPoints\":[{\"x\":1.619792,\"y\":-0.6119792},{\"x\":1.658854,\"y\":-0.9322917}],\"controlPoints\":[{\"x\":1.307292,\"y\":-0.6953125,\"snapped\":false},{\"x\":1.414063,\"y\":-0.903646,\"snapped\":false}]},{\"colorIndex\":9,\"endPoints\":[{\"x\":1.486979,\"y\":-1.179688},{\"x\":0,\"y\":-1.177083}],\"controlPoints\":[{\"x\":0.907986,\"y\":-0.2439238,\"snapped\":false},{\"x\":0.4956596,\"y\":-1.177951,\"snapped\":true}]}],\"connections\":[{\"to\":{\"index\":6,\"end\":1},\"from\":{\"index\":7,\"end\":0}},{\"to\":{\"index\":12,\"end\":0},\"from\":{\"index\":1,\"end\":0}},{\"to\":{\"index\":2,\"end\":1},\"from\":{\"index\":9,\"end\":0}},{\"to\":{\"index\":13,\"end\":0},\"from\":{\"index\":0,\"end\":0}},{\"to\":{\"index\":3,\"end\":0},\"from\":{\"index\":11,\"end\":1}},{\"to\":{\"index\":1,\"end\":1},\"from\":{\"index\":11,\"end\":0}},{\"to\":{\"index\":4,\"end\":0},\"from\":{\"index\":9,\"end\":1}},{\"to\":{\"index\":4,\"end\":1},\"from\":{\"index\":8,\"end\":1}},{\"to\":{\"index\":2,\"end\":0},\"from\":{\"index\":10,\"end\":1}},{\"to\":{\"index\":5,\"end\":1},\"from\":{\"index\":7,\"end\":1}},{\"to\":{\"index\":3,\"end\":1},\"from\":{\"index\":10,\"end\":0}},{\"to\":{\"index\":5,\"end\":0},\"from\":{\"index\":8,\"end\":0}},{\"to\":{\"index\":0,\"end\":1},\"from\":{\"index\":12,\"end\":1}}]},\"minor\":0}"
  },
  {
    "path": "Revolved/model3.rvlvd",
    "content": "{\"major\":1,\"model\":{\"segments\":[{\"colorIndex\":3,\"endPoints\":[{\"x\":0.1927083,\"y\":-0.6458334},{\"x\":0,\"y\":-0.8671876}],\"controlPoints\":[{\"x\":0.1924359,\"y\":-0.8419797,\"snapped\":false},{\"x\":0.07465276,\"y\":-0.8602431,\"snapped\":false}]},{\"colorIndex\":3,\"endPoints\":[{\"x\":0.1953125,\"y\":1.229167},{\"x\":0.1927083,\"y\":-0.6458334}],\"controlPoints\":[{\"x\":0.1944444,\"y\":0.6041669,\"snapped\":true},{\"x\":0.1935764,\"y\":-0.02083325,\"snapped\":true}]},{\"colorIndex\":4,\"endPoints\":[{\"x\":0.3411458,\"y\":1.106771},{\"x\":0.3177083,\"y\":-0.5598959}],\"controlPoints\":[{\"x\":0.3333333,\"y\":0.5512154,\"snapped\":true},{\"x\":0.3255208,\"y\":-0.004340291,\"snapped\":true}]},{\"colorIndex\":4,\"endPoints\":[{\"x\":0.5546875,\"y\":1.075521},{\"x\":0.5442709,\"y\":-0.5286459}],\"controlPoints\":[{\"x\":0.5512153,\"y\":0.5407987,\"snapped\":true},{\"x\":0.5477431,\"y\":0.006076336,\"snapped\":true}]},{\"colorIndex\":4,\"endPoints\":[{\"x\":0.3177083,\"y\":-0.5598959},{\"x\":0.5442709,\"y\":-0.5286459}],\"controlPoints\":[{\"x\":0.3152201,\"y\":-0.7368343,\"snapped\":false},{\"x\":0.5427686,\"y\":-0.7600011,\"snapped\":false}]},{\"colorIndex\":5,\"endPoints\":[{\"x\":0.7083333,\"y\":0.9192709},{\"x\":0.6927084,\"y\":-0.4140625}],\"controlPoints\":[{\"x\":0.703125,\"y\":0.4748264,\"snapped\":true},{\"x\":0.6979167,\"y\":0.03038192,\"snapped\":true}]},{\"colorIndex\":5,\"endPoints\":[{\"x\":0.7083333,\"y\":0.9192709},{\"x\":0.9453126,\"y\":0.9036459}],\"controlPoints\":[{\"x\":0.7108973,\"y\":1.138062,\"snapped\":false},{\"x\":0.9453126,\"y\":1.109375,\"snapped\":false}]},{\"colorIndex\":5,\"endPoints\":[{\"x\":0.9453126,\"y\":0.9036459},{\"x\":0.9453125,\"y\":-0.4114583}],\"controlPoints\":[{\"x\":0.9453126,\"y\":0.4652778,\"snapped\":true},{\"x\":0.9453126,\"y\":0.02690971,\"snapped\":true}]},{\"colorIndex\":6,\"endPoints\":[{\"x\":1.119792,\"y\":0.7317709},{\"x\":1.364583,\"y\":0.7135417}],\"controlPoints\":[{\"x\":1.119792,\"y\":0.9548612,\"snapped\":false},{\"x\":1.365253,\"y\":0.9619137,\"snapped\":false}]},{\"colorIndex\":6,\"endPoints\":[{\"x\":1.364583,\"y\":0.7135417},{\"x\":1.361979,\"y\":-0.2526041}],\"controlPoints\":[{\"x\":1.363715,\"y\":0.3914931,\"snapped\":true},{\"x\":1.362847,\"y\":0.06944448,\"snapped\":true}]},{\"colorIndex\":6,\"endPoints\":[{\"x\":1.119792,\"y\":0.7317709},{\"x\":1.119792,\"y\":-0.25}],\"controlPoints\":[{\"x\":1.119792,\"y\":0.4045139,\"snapped\":true},{\"x\":1.119792,\"y\":0.07725692,\"snapped\":true}]},{\"colorIndex\":7,\"endPoints\":[{\"x\":1.518229,\"y\":0.5312501},{\"x\":1.515625,\"y\":-0.09635417}],\"controlPoints\":[{\"x\":1.517361,\"y\":0.3220487,\"snapped\":true},{\"x\":1.516493,\"y\":0.1128472,\"snapped\":true}]},{\"colorIndex\":7,\"endPoints\":[{\"x\":1.518229,\"y\":0.5312501},{\"x\":1.729167,\"y\":0.5286459}],\"controlPoints\":[{\"x\":1.519166,\"y\":0.7568866,\"snapped\":false},{\"x\":1.7336,\"y\":0.7440897,\"snapped\":false}]},{\"colorIndex\":7,\"endPoints\":[{\"x\":1.729167,\"y\":0.5286459},{\"x\":1.716146,\"y\":-0.1041667}],\"controlPoints\":[{\"x\":1.724827,\"y\":0.3177083,\"snapped\":true},{\"x\":1.720486,\"y\":0.1067708,\"snapped\":true}]},{\"colorIndex\":8,\"endPoints\":[{\"x\":1.856771,\"y\":0.3515625},{\"x\":2.057292,\"y\":0.3463542}],\"controlPoints\":[{\"x\":1.85226,\"y\":0.5064255,\"snapped\":false},{\"x\":2.050307,\"y\":0.5122332,\"snapped\":false}]},{\"colorIndex\":8,\"endPoints\":[{\"x\":2.057292,\"y\":0.3463542},{\"x\":2.067708,\"y\":0.09895834}],\"controlPoints\":[{\"x\":2.060764,\"y\":0.2638889,\"snapped\":true},{\"x\":2.064236,\"y\":0.1814236,\"snapped\":true}]},{\"colorIndex\":8,\"endPoints\":[{\"x\":1.856771,\"y\":0.3515625},{\"x\":1.864583,\"y\":0.08333334}],\"controlPoints\":[{\"x\":1.859375,\"y\":0.2621528,\"snapped\":true},{\"x\":1.861979,\"y\":0.1727431,\"snapped\":true}]},{\"colorIndex\":4,\"endPoints\":[{\"x\":0.3411458,\"y\":1.106771},{\"x\":0.5546875,\"y\":1.075521}],\"controlPoints\":[{\"x\":0.3438626,\"y\":1.299966,\"snapped\":false},{\"x\":0.55601,\"y\":1.27919,\"snapped\":false}]},{\"colorIndex\":3,\"endPoints\":[{\"x\":0.1953125,\"y\":1.229167},{\"x\":0,\"y\":1.479167}],\"controlPoints\":[{\"x\":0.1955862,\"y\":1.426273,\"snapped\":false},{\"x\":0.05729163,\"y\":1.466146,\"snapped\":false}]},{\"colorIndex\":8,\"endPoints\":[{\"x\":1.864583,\"y\":0.08333334},{\"x\":2.067708,\"y\":0.09895834}],\"controlPoints\":[{\"x\":1.869369,\"y\":-0.08096903,\"snapped\":false},{\"x\":2.073127,\"y\":-0.02973347,\"snapped\":false}]},{\"colorIndex\":7,\"endPoints\":[{\"x\":1.515625,\"y\":-0.09635417},{\"x\":1.716146,\"y\":-0.1041667}],\"controlPoints\":[{\"x\":1.514944,\"y\":-0.260385,\"snapped\":false},{\"x\":1.712801,\"y\":-0.2667493,\"snapped\":false}]},{\"colorIndex\":6,\"endPoints\":[{\"x\":1.119792,\"y\":-0.25},{\"x\":1.361979,\"y\":-0.2526041}],\"controlPoints\":[{\"x\":1.119792,\"y\":-0.4461805,\"snapped\":false},{\"x\":1.361491,\"y\":-0.4338509,\"snapped\":false}]},{\"colorIndex\":5,\"endPoints\":[{\"x\":0.6927084,\"y\":-0.4140625},{\"x\":0.9453125,\"y\":-0.4114583}],\"controlPoints\":[{\"x\":0.6904345,\"y\":-0.6081039,\"snapped\":false},{\"x\":0.9453125,\"y\":-0.5920138,\"snapped\":false}]}],\"connections\":[{\"to\":{\"index\":7,\"end\":1},\"from\":{\"index\":22,\"end\":1}},{\"to\":{\"index\":7,\"end\":0},\"from\":{\"index\":6,\"end\":1}},{\"to\":{\"index\":2,\"end\":0},\"from\":{\"index\":17,\"end\":0}},{\"to\":{\"index\":2,\"end\":1},\"from\":{\"index\":4,\"end\":0}},{\"to\":{\"index\":1,\"end\":1},\"from\":{\"index\":0,\"end\":0}},{\"to\":{\"index\":3,\"end\":0},\"from\":{\"index\":17,\"end\":1}},{\"to\":{\"index\":9,\"end\":1},\"from\":{\"index\":21,\"end\":1}},{\"to\":{\"index\":15,\"end\":1},\"from\":{\"index\":19,\"end\":1}},{\"to\":{\"index\":16,\"end\":0},\"from\":{\"index\":14,\"end\":0}},{\"to\":{\"index\":15,\"end\":0},\"from\":{\"index\":14,\"end\":1}},{\"to\":{\"index\":16,\"end\":1},\"from\":{\"index\":19,\"end\":0}},{\"to\":{\"index\":5,\"end\":1},\"from\":{\"index\":22,\"end\":0}},{\"to\":{\"index\":13,\"end\":1},\"from\":{\"index\":20,\"end\":1}},{\"to\":{\"index\":13,\"end\":0},\"from\":{\"index\":12,\"end\":1}},{\"to\":{\"index\":11,\"end\":0},\"from\":{\"index\":12,\"end\":0}},{\"to\":{\"index\":3,\"end\":1},\"from\":{\"index\":4,\"end\":1}},{\"to\":{\"index\":5,\"end\":0},\"from\":{\"index\":6,\"end\":0}},{\"to\":{\"index\":1,\"end\":0},\"from\":{\"index\":18,\"end\":0}},{\"to\":{\"index\":10,\"end\":0},\"from\":{\"index\":8,\"end\":0}},{\"to\":{\"index\":11,\"end\":1},\"from\":{\"index\":20,\"end\":0}},{\"to\":{\"index\":9,\"end\":0},\"from\":{\"index\":8,\"end\":1}},{\"to\":{\"index\":10,\"end\":1},\"from\":{\"index\":21,\"end\":0}}]},\"minor\":0}"
  },
  {
    "path": "Revolved Tests/RVConnectionTests.m",
    "content": "//\n//  RVConnectionTests.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <XCTest/XCTest.h>\n#import <GLKit/GLKit.h>\n\n\n#import \"RVSegment.h\"\n#import \"RVEndPoint.h\"\n#import \"RVAnchorPoint.h\"\n#import \"RVControlPoint.h\"\n\n@interface RVConnectionTests : XCTestCase\n\n@end\n\n@implementation RVConnectionTests\n\n\n- (void)testExample\n{\n    RVSegment *segment1 = [[RVSegment alloc] init];\n    [[segment1 endPointAtSegmentEnd:SegmentEndFirst] setPosition:GLKVector2Make(2.34, 3.0)];\n    [[segment1 endPointAtSegmentEnd:SegmentEndSecond] setPosition:GLKVector2Make(4.0, 20.0)];\n    \n    \n    RVSegment *segment2 = [[RVSegment alloc] init];\n    [[segment2 endPointAtSegmentEnd:SegmentEndFirst] setPosition:GLKVector2Make(2.34, 3.0)];\n    [[segment2 endPointAtSegmentEnd:SegmentEndSecond] setPosition:GLKVector2Make(4.0, 20.0)];\n    \n    [RVSegmentConnection connectSegment:segment1 bySegmentEnd:SegmentEndFirst toSegment:segment2 atSegmentEnd:SegmentEndSecond];\n    \n    XCTAssertNil([segment2 connectionAtSegmentEnd:SegmentEndFirst], @\"\");\n    XCTAssertNil([segment1 connectionAtSegmentEnd:SegmentEndSecond], @\"\");\n    XCTAssertNotNil([segment1 connectionAtSegmentEnd:SegmentEndFirst], @\"\");\n    XCTAssertNotNil([segment2 connectionAtSegmentEnd:SegmentEndSecond], @\"\");\n    \n    \n    RVSegmentConnection *connection = [segment1 connectionAtSegmentEnd:SegmentEndFirst];\n    \n    XCTAssertEqual(connection.aEnd, SegmentEndFirst, @\"\");\n    XCTAssertEqual(connection.bEnd, SegmentEndSecond, @\"\");\n    \n    \n    XCTAssertEqualObjects(connection.a, segment1, @\"\");\n    XCTAssertEqualObjects(connection.b, segment2, @\"\");\n}\n\n    \n\n@end\n"
  },
  {
    "path": "Revolved Tests/RVSerializerTests.m",
    "content": "//\n//  RVSerializerTests.m\n//  Revolved\n//\n//  Created by Bartosz Ciechanowski on 23.08.2013.\n//  Copyright (c) 2013 Bartosz Ciechanowski. All rights reserved.\n//\n\n#import <XCTest/XCTest.h>\n#import <GLKit/GLKit.h>\n\n#import \"RVModelSerializer.h\"\n\n#import \"RVSegment.h\"\n#import \"RVEndPoint.h\"\n#import \"RVAnchorPoint.h\"\n#import \"RVControlPoint.h\"\n\n@interface RVSerializerTests : XCTestCase\n\n@end\n\n@implementation RVSerializerTests\n\n\n- (void)testSimpleSerialization\n{\n    RVSegment *segment = [[RVSegment alloc] init];\n    [[segment endPointAtSegmentEnd:SegmentEndFirst] setPosition:GLKVector2Make(2.34, 3.0)];\n    [[segment endPointAtSegmentEnd:SegmentEndSecond] setPosition:GLKVector2Make(4.0, 20.0)];\n    \n    [[segment controlPointAtSegmentEnd:SegmentEndFirst] setPosition:GLKVector2Make(5.0, -7.0)];\n    [[segment controlPointAtSegmentEnd:SegmentEndSecond] setPosition:GLKVector2Make(1.54, M_PI)];\n    \n    [[segment anchorPointAtSegmentEnd:SegmentEndFirst] setHasControlPoint:YES];\n    [[segment anchorPointAtSegmentEnd:SegmentEndSecond] setHasControlPoint:NO];\n    \n    NSError *error;\n    NSDictionary *dict = [RVModelSerializer JSONModelDictionaryFromSegments:[NSSet setWithObject:segment]];\n    NSSet *segments = [RVModelSerializer segmentsFromJSONModelDictionary:dict error:&error];\n    \n    XCTAssertTrue(error == nil, @\"\");\n    XCTAssertTrue(segments.count == 1, @\"\");\n    \n    RVSegment *parsedSeg = [segments anyObject];\n\n    \n    XCTAssertEqual([[parsedSeg anchorPointAtSegmentEnd:SegmentEndFirst] hasControlPoint],\n                   [[segment anchorPointAtSegmentEnd:SegmentEndFirst] hasControlPoint],\n                   @\"\");\n    \n    XCTAssertEqual([[parsedSeg anchorPointAtSegmentEnd:SegmentEndSecond] hasControlPoint],\n                   [[segment anchorPointAtSegmentEnd:SegmentEndSecond] hasControlPoint],\n                   @\"\");\n}\n\n- (void)testWrongInputSerialization\n{\n    NSError *error;\n    NSSet *segments;\n    \n    segments = [RVModelSerializer segmentsFromJSONModelDictionary:nil error:&error];\n    XCTAssertNil(segments, @\"\");\n\n    segments = [RVModelSerializer segmentsFromJSONModelDictionary:@{} error:&error];\n    XCTAssertNil(segments, @\"\");\n\n    segments = [RVModelSerializer segmentsFromJSONModelDictionary:@{@\"segments\" : @{}, @\"connections\" : @[]} error:&error];\n    XCTAssertNil(segments, @\"\");\n\n    segments = [RVModelSerializer segmentsFromJSONModelDictionary:@{@\"segments\" : @[], @\"connections\" : @{}} error:&error];\n    XCTAssertNil(segments, @\"\");\n}\n\n\n- (void)testConnectionSerialization\n{\n    RVSegment *segment1 = [[RVSegment alloc] init];\n    [[segment1 endPointAtSegmentEnd:SegmentEndFirst] setPosition:GLKVector2Make(2.34, 3.0)];\n    [[segment1 endPointAtSegmentEnd:SegmentEndSecond] setPosition:GLKVector2Make(4.0, 20.0)];\n    \n    \n    RVSegment *segment2 = [[RVSegment alloc] init];\n    [[segment2 endPointAtSegmentEnd:SegmentEndFirst] setPosition:GLKVector2Make(2.34, 3.0)];\n    [[segment2 endPointAtSegmentEnd:SegmentEndSecond] setPosition:GLKVector2Make(4.0, 20.0)];\n    \n    [RVSegmentConnection connectSegment:segment1 bySegmentEnd:SegmentEndFirst toSegment:segment2 atSegmentEnd:SegmentEndSecond];\n    \n    NSError *error;\n    NSDictionary *dict = [RVModelSerializer JSONModelDictionaryFromSegments:[NSSet setWithObjects:segment1, segment2, nil]];\n    NSSet *segments = [RVModelSerializer segmentsFromJSONModelDictionary:dict error:&error];\n    \n    XCTAssertTrue(error == nil, @\"\");\n    XCTAssertTrue(segments.count == 2, @\"\");\n    \n    RVSegment *parsedSeg = [segments anyObject];\n    RVSegmentConnection *connection = [parsedSeg connectionAtSegmentEnd:SegmentEndFirst] ?: [parsedSeg connectionAtSegmentEnd:SegmentEndSecond];\n    \n\n    XCTAssertEqual([connection aEnd],\n                   SegmentEndFirst,\n                   @\"\");\n\n    XCTAssertEqual([connection bEnd],\n                   SegmentEndSecond,\n                   @\"\");\n    \n    \n    XCTAssertNotNil([connection a], @\"\");\n    XCTAssertNotNil([connection b], @\"\");\n    XCTAssertNotEqualObjects(connection.a, connection.b, @\"\");\n}\n\n@end\n"
  },
  {
    "path": "Revolved Tests/Revolved Tests-Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>BartoszCiechanowski.${PRODUCT_NAME:rfc1034identifier}</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Revolved Tests/Revolved Tests-Prefix.pch",
    "content": "//\n//  Prefix header\n//\n//  The contents of this file are implicitly included at the beginning of every source file.\n//\n\n#ifdef __OBJC__\n    #import <UIKit/UIKit.h>\n    #import <Foundation/Foundation.h>\n#endif\n"
  },
  {
    "path": "Revolved Tests/en.lproj/InfoPlist.strings",
    "content": "/* Localized versions of Info.plist keys */\n\n"
  },
  {
    "path": "Revolved.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t980CC35C17F0AEAE0057D5AD /* RVSettingsButtonsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 980CC35B17F0AEAE0057D5AD /* RVSettingsButtonsView.m */; };\n\t\t980CC35E17F0AECD0057D5AD /* RVSettingsButtonsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 980CC35D17F0AECD0057D5AD /* RVSettingsButtonsView.xib */; };\n\t\t981395A917DD144700C17CB1 /* RVQuaternionAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 981395A817DD144700C17CB1 /* RVQuaternionAnimation.m */; };\n\t\t98294FAC17CFD852003CAE5F /* NSArray+Functional.m in Sources */ = {isa = PBXBuildFile; fileRef = 98294FAB17CFD852003CAE5F /* NSArray+Functional.m */; };\n\t\t98294FB017D354A1003CAE5F /* NSError+RevolvedErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 98294FAF17D354A1003CAE5F /* NSError+RevolvedErrors.m */; };\n\t\t98294FB317D361C6003CAE5F /* RVModelMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 98294FB217D361C6003CAE5F /* RVModelMetadata.m */; };\n\t\t98294FBB17D53157003CAE5F /* RVAxisShader.m in Sources */ = {isa = PBXBuildFile; fileRef = 98294FBA17D53157003CAE5F /* RVAxisShader.m */; };\n\t\t98294FBE17D5325A003CAE5F /* RVAxisShader.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 98294FBC17D5325A003CAE5F /* RVAxisShader.vsh */; };\n\t\t98294FBF17D5325A003CAE5F /* RVAxisShader.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 98294FBD17D5325A003CAE5F /* RVAxisShader.fsh */; };\n\t\t982D8D0217DCDEB6004C273F /* RVRootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 982D8D0117DCDEB6004C273F /* RVRootViewController.xib */; };\n\t\t9832A665186DEB7A003501AE /* RVExportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9832A663186DEB7A003501AE /* RVExportViewController.m */; };\n\t\t9832A666186DEB7A003501AE /* RVExportViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9832A664186DEB7A003501AE /* RVExportViewController.xib */; };\n\t\t9832A66C186E0E72003501AE /* SSZipArchive.m in Sources */ = {isa = PBXBuildFile; fileRef = 9832A66A186E0E72003501AE /* SSZipArchive.m */; };\n\t\t9832A66E186E0EE2003501AE /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9832A66D186E0EE2003501AE /* libz.dylib */; };\n\t\t9832A679186E0F98003501AE /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 9832A671186E0F98003501AE /* ioapi.c */; };\n\t\t9832A67A186E0F98003501AE /* mztools.c in Sources */ = {isa = PBXBuildFile; fileRef = 9832A673186E0F98003501AE /* mztools.c */; };\n\t\t9832A67B186E0F98003501AE /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 9832A675186E0F98003501AE /* unzip.c */; };\n\t\t9832A67C186E0F98003501AE /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 9832A677186E0F98003501AE /* zip.c */; };\n\t\t98475ACE17C0D232002FD2AB /* RVColorProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 98475ACD17C0D232002FD2AB /* RVColorProvider.m */; };\n\t\t9850E0AC17F74376006B8ACD /* UIView+RotationAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 9850E0AB17F74376006B8ACD /* UIView+RotationAnimation.m */; };\n\t\t9852517D17BC09C600B348F4 /* RVColorPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9852517C17BC09C600B348F4 /* RVColorPicker.m */; };\n\t\t9852518217BD1F8400B348F4 /* RVAnchorPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 9852518117BD1F8400B348F4 /* RVAnchorPoint.m */; };\n\t\t9852518517BD1F9300B348F4 /* RVControlPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 9852518417BD1F9300B348F4 /* RVControlPoint.m */; };\n\t\t9852518817BD1F9C00B348F4 /* RVEndPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 9852518717BD1F9C00B348F4 /* RVEndPoint.m */; };\n\t\t9852518E17BD324900B348F4 /* RVPointShader.m in Sources */ = {isa = PBXBuildFile; fileRef = 9852518D17BD324900B348F4 /* RVPointShader.m */; };\n\t\t9852519117BD326600B348F4 /* RVPointShader.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 9852518F17BD326600B348F4 /* RVPointShader.vsh */; };\n\t\t9852519217BD326600B348F4 /* RVPointShader.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 9852519017BD326600B348F4 /* RVPointShader.fsh */; };\n\t\t9852519517BEC58200B348F4 /* RVDeleteView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9852519417BEC58200B348F4 /* RVDeleteView.m */; };\n\t\t98557F5E17D53E7D0062472B /* RVAxisMeshController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98B5C18717D5343000889553 /* RVAxisMeshController.m */; };\n\t\t98557F6417D6758D0062472B /* RVAxisSprite.m in Sources */ = {isa = PBXBuildFile; fileRef = 98557F6317D6758D0062472B /* RVAxisSprite.m */; };\n\t\t98557F6717D7C6190062472B /* RVGuidelineDotSprite.m in Sources */ = {isa = PBXBuildFile; fileRef = 98557F6617D7C6190062472B /* RVGuidelineDotSprite.m */; };\n\t\t98557F6A17D7CB300062472B /* RVGuidlineDotMeshController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98557F6917D7CB300062472B /* RVGuidlineDotMeshController.m */; };\n\t\t98557F6D17DCD26A0062472B /* RVRenderingController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98557F6C17DCD26A0062472B /* RVRenderingController.m */; };\n\t\t9859CA1317E625AC000E539F /* NSMutableArray+MoveObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 9859CA1217E625AC000E539F /* NSMutableArray+MoveObject.m */; };\n\t\t9859CA1617E627BA000E539F /* NSMutableOrderedSet+MoveObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 9859CA1517E627BA000E539F /* NSMutableOrderedSet+MoveObject.m */; };\n\t\t9859CA1E17E651B4000E539F /* RVAddProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9859CA1D17E651B4000E539F /* RVAddProgressView.m */; };\n\t\t985E10D917C946E600BE4C28 /* RVModelSprite.m in Sources */ = {isa = PBXBuildFile; fileRef = 985E10D817C946E600BE4C28 /* RVModelSprite.m */; };\n\t\t985E10DC17CA54F300BE4C28 /* NSMapTable+BlockEnumeration.m in Sources */ = {isa = PBXBuildFile; fileRef = 985E10DB17CA54F300BE4C28 /* NSMapTable+BlockEnumeration.m */; };\n\t\t985E10E117CA688400BE4C28 /* RVAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 985E10E017CA688400BE4C28 /* RVAnimator.m */; };\n\t\t985E10E517CA691100BE4C28 /* RVAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 985E10E417CA691100BE4C28 /* RVAnimation.m */; };\n\t\t985E10E817CA6B1600BE4C28 /* RVFloatAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 985E10E717CA6B1600BE4C28 /* RVFloatAnimation.m */; };\n\t\t985E10EB17CA6B2200BE4C28 /* RVVectorAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 985E10EA17CA6B2200BE4C28 /* RVVectorAnimation.m */; };\n\t\t985E10EF17CA778C00BE4C28 /* RVDrawViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 985E10EE17CA778C00BE4C28 /* RVDrawViewController.xib */; };\n\t\t9861247E17C7FA290051C092 /* RVModelManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9861247D17C7FA290051C092 /* RVModelManager.m */; };\n\t\t9861248317C7FCC80051C092 /* RVModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9861248217C7FCC80051C092 /* RVModel.m */; };\n\t\t9861248717C8012D0051C092 /* RVModelCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9861248617C8012D0051C092 /* RVModelCell.m */; };\n\t\t9861248E17C802060051C092 /* UIColor+RevolvedColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 9861248D17C802060051C092 /* UIColor+RevolvedColors.m */; };\n\t\t9861249417C8DDBB0051C092 /* RVRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9861249317C8DDBB0051C092 /* RVRootViewController.m */; };\n\t\t986C0C3F183816F300F8F51D /* RVOBJExporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 986C0C3E183816F300F8F51D /* RVOBJExporter.m */; };\n\t\t9872E2F117EB17E2000385EC /* mail.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9872E2F017EB17E2000385EC /* mail.txt */; };\n\t\t9872E2F417EBA5A9000385EC /* RVUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 9872E2F317EBA5A9000385EC /* RVUserDefaults.m */; };\n\t\t9872E2FB17EDF2BB000385EC /* RVTutorialPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9872E2FA17EDF2BB000385EC /* RVTutorialPage.m */; };\n\t\t9872E2FF17EDF37D000385EC /* RVTutorialViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9872E2FD17EDF37D000385EC /* RVTutorialViewController.m */; };\n\t\t9872E30017EDF37D000385EC /* RVTutorialViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9872E2FE17EDF37D000385EC /* RVTutorialViewController.xib */; };\n\t\t9872E30217EF144C000385EC /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9872E30117EF144C000385EC /* Social.framework */; };\n\t\t9872E30417EF1470000385EC /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9872E30317EF1470000385EC /* Twitter.framework */; };\n\t\t9872E30617EF159D000385EC /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9872E30517EF159D000385EC /* AssetsLibrary.framework */; };\n\t\t9873945317C200910067FED5 /* RVSprite.m in Sources */ = {isa = PBXBuildFile; fileRef = 9873945217C200910067FED5 /* RVSprite.m */; };\n\t\t9873945717C200B40067FED5 /* RVLineSprite.m in Sources */ = {isa = PBXBuildFile; fileRef = 9873945617C200B40067FED5 /* RVLineSprite.m */; };\n\t\t9873945A17C200FC0067FED5 /* RVPointSprite.m in Sources */ = {isa = PBXBuildFile; fileRef = 9873945917C200FC0067FED5 /* RVPointSprite.m */; };\n\t\t9873945E17C400BB0067FED5 /* RVModelsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9873945C17C400BB0067FED5 /* RVModelsViewController.m */; };\n\t\t9873945F17C400BB0067FED5 /* RVModelsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9873945D17C400BB0067FED5 /* RVModelsViewController.xib */; };\n\t\t9873946117C400D30067FED5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9873946017C400D30067FED5 /* Images.xcassets */; };\n\t\t9873946717C405130067FED5 /* RVPictureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9873946517C405130067FED5 /* RVPictureViewController.m */; };\n\t\t9873946817C405130067FED5 /* RVPictureViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9873946617C405130067FED5 /* RVPictureViewController.xib */; };\n\t\t9873946D17C53F0E0067FED5 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9873946C17C53F0E0067FED5 /* AVFoundation.framework */; };\n\t\t9873946F17C540680067FED5 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9873946E17C540680067FED5 /* CoreVideo.framework */; };\n\t\t9873947317C559790067FED5 /* RVOpenGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9873947217C559790067FED5 /* RVOpenGLView.m */; };\n\t\t9873947517C562050067FED5 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9873947417C562050067FED5 /* QuartzCore.framework */; };\n\t\t988180C617F2361200C0E6BD /* MFMailComposeViewController+SendIfPossible.m in Sources */ = {isa = PBXBuildFile; fileRef = 988180C517F2361200C0E6BD /* MFMailComposeViewController+SendIfPossible.m */; };\n\t\t988180C817F385E700C0E6BD /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 988180C717F385E700C0E6BD /* StoreKit.framework */; };\n\t\t98A3451917B6CAD500D0C82F /* RVPointMeshController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98A3451817B6CAD500D0C82F /* RVPointMeshController.m */; };\n\t\t98A3451C17B6CAE700D0C82F /* RVMeshController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98A3451B17B6CAE700D0C82F /* RVMeshController.m */; };\n\t\t98A3452117B7A16300D0C82F /* RVSegmentConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 98A3452017B7A16300D0C82F /* RVSegmentConnection.m */; };\n\t\t98A3452417B7AD2900D0C82F /* RVGuideline.m in Sources */ = {isa = PBXBuildFile; fileRef = 98A3452317B7AD2900D0C82F /* RVGuideline.m */; };\n\t\t98A9800517E8FCD500F09CFD /* RVModelButtonsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 98A9800417E8FCD500F09CFD /* RVModelButtonsView.m */; };\n\t\t98A9800717E8FCDF00F09CFD /* RVModelButtonsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98A9800617E8FCDF00F09CFD /* RVModelButtonsView.xib */; };\n\t\t98A9800B17E8FD9500F09CFD /* RVPreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98A9800917E8FD9500F09CFD /* RVPreviewViewController.m */; };\n\t\t98A9800C17E8FD9500F09CFD /* RVPreviewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98A9800A17E8FD9500F09CFD /* RVPreviewViewController.xib */; };\n\t\t98ADF00317FCB44200D58007 /* RVSelectTutorialPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 98ADF00217FCB44200D58007 /* RVSelectTutorialPage.m */; };\n\t\t98ADF00517FCB44900D58007 /* RVSelectTutorialPage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98ADF00417FCB44900D58007 /* RVSelectTutorialPage.xib */; };\n\t\t98ADF01017FCBE7000D58007 /* RVPassForwardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 98ADF00F17FCBE7000D58007 /* RVPassForwardView.m */; };\n\t\t98ADF01B17FDF85C00D58007 /* RVFinishTutorialPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 98ADF01A17FDF85C00D58007 /* RVFinishTutorialPage.m */; };\n\t\t98ADF01D17FDF86200D58007 /* RVFinishTutorialPage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98ADF01C17FDF86200D58007 /* RVFinishTutorialPage.xib */; };\n\t\t98B8E48C17FB3ECD002F8DDB /* RVSegmentsTutorialPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 98B8E48B17FB3ECD002F8DDB /* RVSegmentsTutorialPage.m */; };\n\t\t98B8E48E17FB3EDE002F8DDB /* RVSegmentsTutorialPage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98B8E48D17FB3EDE002F8DDB /* RVSegmentsTutorialPage.xib */; };\n\t\t98B8E49917FB5233002F8DDB /* RVDrawingTutorialPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 98B8E49817FB5233002F8DDB /* RVDrawingTutorialPage.m */; };\n\t\t98B8E49B17FB5249002F8DDB /* RVDrawingTutorialPage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98B8E49A17FB5249002F8DDB /* RVDrawingTutorialPage.xib */; };\n\t\t98B8E4A817FB5FA1002F8DDB /* RVRevolvedTutorialPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 98B8E4A717FB5FA1002F8DDB /* RVRevolvedTutorialPage.m */; };\n\t\t98B8E4AA17FB5FAC002F8DDB /* RVRevolvedTutorialPage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98B8E4A917FB5FAC002F8DDB /* RVRevolvedTutorialPage.xib */; };\n\t\t98B8E4AD17FB695F002F8DDB /* RVTutorialLineImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 98B8E4AC17FB695F002F8DDB /* RVTutorialLineImageView.m */; };\n\t\t98B8E4B517FB757B002F8DDB /* RVRevolvedTutorialPageSolid.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98B8E4B417FB757A002F8DDB /* RVRevolvedTutorialPageSolid.xib */; };\n\t\t98B8E4C217FC87BE002F8DDB /* RVBendTutorialPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 98B8E4C117FC87BE002F8DDB /* RVBendTutorialPage.m */; };\n\t\t98B8E4C417FC87C5002F8DDB /* RVBendTutorialPage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98B8E4C317FC87C4002F8DDB /* RVBendTutorialPage.xib */; };\n\t\t98B8E4C717FCB2BD002F8DDB /* RVStartTutorialPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 98B8E4C617FCB2BD002F8DDB /* RVStartTutorialPage.m */; };\n\t\t98B8E4C917FCB2C3002F8DDB /* RVStartTutorialPage.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98B8E4C817FCB2C3002F8DDB /* RVStartTutorialPage.xib */; };\n\t\t98C5FE9417B2B56800022331 /* RVDrawViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98C5FE9317B2B56800022331 /* RVDrawViewController.m */; };\n\t\t98C5FE9C17B2BAFD00022331 /* RVModelViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98C5FE9617B2B96100022331 /* RVModelViewController.xib */; };\n\t\t98C5FE9F17B2BC9D00022331 /* RVSpaceConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 98C5FE9E17B2BC9D00022331 /* RVSpaceConverter.m */; };\n\t\t98C5FEA217B2CA0300022331 /* RVLineMeshController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98C5FEA117B2CA0300022331 /* RVLineMeshController.m */; };\n\t\t98C5FEA617B2D8AC00022331 /* RVLineShader.m in Sources */ = {isa = PBXBuildFile; fileRef = 98C5FEA517B2D8AC00022331 /* RVLineShader.m */; };\n\t\t98C5FEA917B2D93700022331 /* RVLineShader.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 98C5FEA717B2D93700022331 /* RVLineShader.fsh */; };\n\t\t98C5FEAA17B2D93700022331 /* RVLineShader.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 98C5FEA817B2D93700022331 /* RVLineShader.vsh */; };\n\t\t98C5FEAD17B2EFCD00022331 /* DrawGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 98C5FEAC17B2EFCD00022331 /* DrawGestureRecognizer.m */; };\n\t\t98C5FEB317B65EE400022331 /* RVDrawController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98C5FEB217B65EE400022331 /* RVDrawController.m */; };\n\t\t98C5FEB917B66BEB00022331 /* RVPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 98C5FEB817B66BEB00022331 /* RVPoint.m */; };\n\t\t98CD44DA18303F0D004D1986 /* RVExporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 98CD44D918303F0D004D1986 /* RVExporter.m */; };\n\t\t98CD44DD18304056004D1986 /* RVSTLExporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 98CD44DC18304056004D1986 /* RVSTLExporter.m */; };\n\t\t98D6BA0717F0EF2200BFEDB4 /* RVCreditsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D6BA0517F0EF2200BFEDB4 /* RVCreditsViewController.m */; };\n\t\t98D6BA0817F0EF2200BFEDB4 /* RVCreditsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98D6BA0617F0EF2200BFEDB4 /* RVCreditsViewController.xib */; };\n\t\t98EAA2301804AC6800D0B527 /* RVTutorialScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 98EAA22F1804AC6800D0B527 /* RVTutorialScrollView.m */; };\n\t\t98ED503017C7CCDA00E5FE1F /* RVModelSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 98ED502F17C7CCDA00E5FE1F /* RVModelSerializer.m */; };\n\t\t98FADE5217EB118E00E1DFE0 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FADE5117EB118E00E1DFE0 /* MessageUI.framework */; };\n\t\t98FB7E6C17AD75D3000262F2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FB7E6B17AD75D3000262F2 /* UIKit.framework */; };\n\t\t98FB7E6E17AD75D3000262F2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FB7E6D17AD75D3000262F2 /* Foundation.framework */; };\n\t\t98FB7E7017AD75D3000262F2 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FB7E6F17AD75D3000262F2 /* CoreGraphics.framework */; };\n\t\t98FB7E7617AD75D3000262F2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 98FB7E7417AD75D3000262F2 /* InfoPlist.strings */; };\n\t\t98FB7E7817AD75D3000262F2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7E7717AD75D3000262F2 /* main.m */; };\n\t\t98FB7E7C17AD75D3000262F2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7E7B17AD75D3000262F2 /* AppDelegate.m */; };\n\t\t98FB7E9117AD76BF000262F2 /* RVSegment.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7E9017AD76BF000262F2 /* RVSegment.m */; };\n\t\t98FB7E9917AD785A000262F2 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FB7E9817AD785A000262F2 /* GLKit.framework */; };\n\t\t98FB7E9D17AD78F0000262F2 /* RVModelViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7E9C17AD78F0000262F2 /* RVModelViewController.m */; };\n\t\t98FB7EAE17AD7F21000262F2 /* CameraController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7EAD17AD7EF7000262F2 /* CameraController.m */; };\n\t\t98FB7EB117AD7FD4000262F2 /* Camera.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7EB017AD7FD4000262F2 /* Camera.m */; };\n\t\t98FB7EBA17AD8480000262F2 /* RVModelMeshController.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7EB717AD8480000262F2 /* RVModelMeshController.m */; };\n\t\t98FB7EBB17AD8480000262F2 /* Renderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7EB917AD8480000262F2 /* Renderer.m */; };\n\t\t98FB7EC517AD864A000262F2 /* BCShader.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7EC017AD864A000262F2 /* BCShader.m */; };\n\t\t98FB7EC617AD864A000262F2 /* RVModelShader.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FB7EC217AD864A000262F2 /* RVModelShader.m */; };\n\t\t98FB7EC717AD864A000262F2 /* RVModelShader.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 98FB7EC317AD864A000262F2 /* RVModelShader.vsh */; };\n\t\t98FB7EC817AD864A000262F2 /* RVModelShader.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 98FB7EC417AD864A000262F2 /* RVModelShader.fsh */; };\n\t\t98FB7ECE17B03B65000262F2 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FB7ECD17B03B65000262F2 /* OpenGLES.framework */; };\n\t\t98FDDB37180176A000F16136 /* noise.png in Resources */ = {isa = PBXBuildFile; fileRef = 98FDDB36180176A000F16136 /* noise.png */; };\n\t\t98FDDB39180176AD00F16136 /* sprites.png in Resources */ = {isa = PBXBuildFile; fileRef = 98FDDB38180176AD00F16136 /* sprites.png */; };\n\t\t98FDDB3C1801930F00F16136 /* RVColorPickerButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 98FDDB3B1801930F00F16136 /* RVColorPickerButton.m */; };\n\t\t98FDDB401801E4A600F16136 /* model1.rvlvd in Resources */ = {isa = PBXBuildFile; fileRef = 98FDDB3D1801E4A600F16136 /* model1.rvlvd */; };\n\t\t98FDDB411801E4A600F16136 /* model2.rvlvd in Resources */ = {isa = PBXBuildFile; fileRef = 98FDDB3E1801E4A600F16136 /* model2.rvlvd */; };\n\t\t98FDDB421801E4A600F16136 /* model3.rvlvd in Resources */ = {isa = PBXBuildFile; fileRef = 98FDDB3F1801E4A600F16136 /* model3.rvlvd */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t980CC35A17F0AEAE0057D5AD /* RVSettingsButtonsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVSettingsButtonsView.h; sourceTree = \"<group>\"; };\n\t\t980CC35B17F0AEAE0057D5AD /* RVSettingsButtonsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVSettingsButtonsView.m; sourceTree = \"<group>\"; };\n\t\t980CC35D17F0AECD0057D5AD /* RVSettingsButtonsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVSettingsButtonsView.xib; sourceTree = \"<group>\"; };\n\t\t981395A717DD144700C17CB1 /* RVQuaternionAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVQuaternionAnimation.h; sourceTree = \"<group>\"; };\n\t\t981395A817DD144700C17CB1 /* RVQuaternionAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVQuaternionAnimation.m; sourceTree = \"<group>\"; };\n\t\t98294FAA17CFD852003CAE5F /* NSArray+Functional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"NSArray+Functional.h\"; sourceTree = \"<group>\"; };\n\t\t98294FAB17CFD852003CAE5F /* NSArray+Functional.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"NSArray+Functional.m\"; sourceTree = \"<group>\"; };\n\t\t98294FAE17D354A1003CAE5F /* NSError+RevolvedErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"NSError+RevolvedErrors.h\"; sourceTree = \"<group>\"; };\n\t\t98294FAF17D354A1003CAE5F /* NSError+RevolvedErrors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"NSError+RevolvedErrors.m\"; sourceTree = \"<group>\"; };\n\t\t98294FB117D361C6003CAE5F /* RVModelMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelMetadata.h; sourceTree = \"<group>\"; };\n\t\t98294FB217D361C6003CAE5F /* RVModelMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelMetadata.m; sourceTree = \"<group>\"; };\n\t\t98294FB917D53157003CAE5F /* RVAxisShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVAxisShader.h; sourceTree = \"<group>\"; };\n\t\t98294FBA17D53157003CAE5F /* RVAxisShader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVAxisShader.m; sourceTree = \"<group>\"; };\n\t\t98294FBC17D5325A003CAE5F /* RVAxisShader.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = RVAxisShader.vsh; sourceTree = \"<group>\"; };\n\t\t98294FBD17D5325A003CAE5F /* RVAxisShader.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = RVAxisShader.fsh; sourceTree = \"<group>\"; };\n\t\t982D8D0117DCDEB6004C273F /* RVRootViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVRootViewController.xib; sourceTree = \"<group>\"; };\n\t\t9832A662186DEB7A003501AE /* RVExportViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVExportViewController.h; sourceTree = \"<group>\"; };\n\t\t9832A663186DEB7A003501AE /* RVExportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVExportViewController.m; sourceTree = \"<group>\"; };\n\t\t9832A664186DEB7A003501AE /* RVExportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVExportViewController.xib; sourceTree = \"<group>\"; };\n\t\t9832A669186E0E72003501AE /* SSZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSZipArchive.h; sourceTree = \"<group>\"; };\n\t\t9832A66A186E0E72003501AE /* SSZipArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSZipArchive.m; sourceTree = \"<group>\"; };\n\t\t9832A66D186E0EE2003501AE /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = \"compiled.mach-o.dylib\"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };\n\t\t9832A670186E0F98003501AE /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = \"<group>\"; };\n\t\t9832A671186E0F98003501AE /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = \"<group>\"; };\n\t\t9832A672186E0F98003501AE /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = \"<group>\"; };\n\t\t9832A673186E0F98003501AE /* mztools.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mztools.c; sourceTree = \"<group>\"; };\n\t\t9832A674186E0F98003501AE /* mztools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mztools.h; sourceTree = \"<group>\"; };\n\t\t9832A675186E0F98003501AE /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = \"<group>\"; };\n\t\t9832A676186E0F98003501AE /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = \"<group>\"; };\n\t\t9832A677186E0F98003501AE /* zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip.c; sourceTree = \"<group>\"; };\n\t\t9832A678186E0F98003501AE /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = \"<group>\"; };\n\t\t98475ACC17C0D232002FD2AB /* RVColorProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVColorProvider.h; sourceTree = \"<group>\"; };\n\t\t98475ACD17C0D232002FD2AB /* RVColorProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVColorProvider.m; sourceTree = \"<group>\"; };\n\t\t9850E0AA17F74376006B8ACD /* UIView+RotationAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"UIView+RotationAnimation.h\"; sourceTree = \"<group>\"; };\n\t\t9850E0AB17F74376006B8ACD /* UIView+RotationAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"UIView+RotationAnimation.m\"; sourceTree = \"<group>\"; };\n\t\t9852517B17BC09C600B348F4 /* RVColorPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVColorPicker.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t9852517C17BC09C600B348F4 /* RVColorPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVColorPicker.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t9852518017BD1F8400B348F4 /* RVAnchorPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVAnchorPoint.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t9852518117BD1F8400B348F4 /* RVAnchorPoint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVAnchorPoint.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t9852518317BD1F9300B348F4 /* RVControlPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVControlPoint.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t9852518417BD1F9300B348F4 /* RVControlPoint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVControlPoint.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t9852518617BD1F9C00B348F4 /* RVEndPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVEndPoint.h; sourceTree = \"<group>\"; };\n\t\t9852518717BD1F9C00B348F4 /* RVEndPoint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVEndPoint.m; sourceTree = \"<group>\"; };\n\t\t9852518917BD2E3700B348F4 /* PointVertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PointVertex.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t9852518C17BD324900B348F4 /* RVPointShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVPointShader.h; sourceTree = \"<group>\"; };\n\t\t9852518D17BD324900B348F4 /* RVPointShader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVPointShader.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t9852518F17BD326600B348F4 /* RVPointShader.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = RVPointShader.vsh; sourceTree = \"<group>\"; };\n\t\t9852519017BD326600B348F4 /* RVPointShader.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = RVPointShader.fsh; sourceTree = \"<group>\"; };\n\t\t9852519317BEC58200B348F4 /* RVDeleteView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVDeleteView.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t9852519417BEC58200B348F4 /* RVDeleteView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVDeleteView.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98557F6217D6758D0062472B /* RVAxisSprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVAxisSprite.h; sourceTree = \"<group>\"; };\n\t\t98557F6317D6758D0062472B /* RVAxisSprite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVAxisSprite.m; sourceTree = \"<group>\"; };\n\t\t98557F6517D7C6190062472B /* RVGuidelineDotSprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVGuidelineDotSprite.h; sourceTree = \"<group>\"; };\n\t\t98557F6617D7C6190062472B /* RVGuidelineDotSprite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVGuidelineDotSprite.m; sourceTree = \"<group>\"; };\n\t\t98557F6817D7CB300062472B /* RVGuidlineDotMeshController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVGuidlineDotMeshController.h; sourceTree = \"<group>\"; };\n\t\t98557F6917D7CB300062472B /* RVGuidlineDotMeshController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVGuidlineDotMeshController.m; sourceTree = \"<group>\"; };\n\t\t98557F6B17DCD26A0062472B /* RVRenderingController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVRenderingController.h; sourceTree = \"<group>\"; };\n\t\t98557F6C17DCD26A0062472B /* RVRenderingController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVRenderingController.m; sourceTree = \"<group>\"; };\n\t\t9859CA1117E625AC000E539F /* NSMutableArray+MoveObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"NSMutableArray+MoveObject.h\"; sourceTree = \"<group>\"; };\n\t\t9859CA1217E625AC000E539F /* NSMutableArray+MoveObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"NSMutableArray+MoveObject.m\"; sourceTree = \"<group>\"; };\n\t\t9859CA1417E627BA000E539F /* NSMutableOrderedSet+MoveObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"NSMutableOrderedSet+MoveObject.h\"; sourceTree = \"<group>\"; };\n\t\t9859CA1517E627BA000E539F /* NSMutableOrderedSet+MoveObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"NSMutableOrderedSet+MoveObject.m\"; sourceTree = \"<group>\"; };\n\t\t9859CA1C17E651B4000E539F /* RVAddProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVAddProgressView.h; sourceTree = \"<group>\"; };\n\t\t9859CA1D17E651B4000E539F /* RVAddProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVAddProgressView.m; sourceTree = \"<group>\"; };\n\t\t985E10D717C946E600BE4C28 /* RVModelSprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelSprite.h; sourceTree = \"<group>\"; };\n\t\t985E10D817C946E600BE4C28 /* RVModelSprite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelSprite.m; sourceTree = \"<group>\"; };\n\t\t985E10DA17CA54F300BE4C28 /* NSMapTable+BlockEnumeration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"NSMapTable+BlockEnumeration.h\"; sourceTree = \"<group>\"; };\n\t\t985E10DB17CA54F300BE4C28 /* NSMapTable+BlockEnumeration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"NSMapTable+BlockEnumeration.m\"; sourceTree = \"<group>\"; };\n\t\t985E10DF17CA688400BE4C28 /* RVAnimator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVAnimator.h; sourceTree = \"<group>\"; };\n\t\t985E10E017CA688400BE4C28 /* RVAnimator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVAnimator.m; sourceTree = \"<group>\"; };\n\t\t985E10E317CA691100BE4C28 /* RVAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVAnimation.h; sourceTree = \"<group>\"; };\n\t\t985E10E417CA691100BE4C28 /* RVAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVAnimation.m; sourceTree = \"<group>\"; };\n\t\t985E10E617CA6B1600BE4C28 /* RVFloatAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVFloatAnimation.h; sourceTree = \"<group>\"; };\n\t\t985E10E717CA6B1600BE4C28 /* RVFloatAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVFloatAnimation.m; sourceTree = \"<group>\"; };\n\t\t985E10E917CA6B2200BE4C28 /* RVVectorAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVVectorAnimation.h; sourceTree = \"<group>\"; };\n\t\t985E10EA17CA6B2200BE4C28 /* RVVectorAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVVectorAnimation.m; sourceTree = \"<group>\"; };\n\t\t985E10EC17CA6B4E00BE4C28 /* RVAnimation_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RVAnimation_Private.h; sourceTree = \"<group>\"; };\n\t\t985E10EE17CA778C00BE4C28 /* RVDrawViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVDrawViewController.xib; sourceTree = \"<group>\"; };\n\t\t9861247A17C7F59E0051C092 /* RVConnectionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVConnectionTests.m; sourceTree = \"<group>\"; };\n\t\t9861247C17C7FA290051C092 /* RVModelManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelManager.h; sourceTree = \"<group>\"; };\n\t\t9861247D17C7FA290051C092 /* RVModelManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelManager.m; sourceTree = \"<group>\"; };\n\t\t9861248117C7FCC80051C092 /* RVModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModel.h; sourceTree = \"<group>\"; };\n\t\t9861248217C7FCC80051C092 /* RVModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModel.m; sourceTree = \"<group>\"; };\n\t\t9861248517C8012D0051C092 /* RVModelCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelCell.h; sourceTree = \"<group>\"; };\n\t\t9861248617C8012D0051C092 /* RVModelCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelCell.m; sourceTree = \"<group>\"; };\n\t\t9861248C17C802060051C092 /* UIColor+RevolvedColors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"UIColor+RevolvedColors.h\"; sourceTree = \"<group>\"; };\n\t\t9861248D17C802060051C092 /* UIColor+RevolvedColors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"UIColor+RevolvedColors.m\"; sourceTree = \"<group>\"; };\n\t\t9861249217C8DDBB0051C092 /* RVRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVRootViewController.h; sourceTree = \"<group>\"; };\n\t\t9861249317C8DDBB0051C092 /* RVRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVRootViewController.m; sourceTree = \"<group>\"; };\n\t\t986C0C3D183816F300F8F51D /* RVOBJExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVOBJExporter.h; sourceTree = \"<group>\"; };\n\t\t986C0C3E183816F300F8F51D /* RVOBJExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVOBJExporter.m; sourceTree = \"<group>\"; };\n\t\t9872E2F017EB17E2000385EC /* mail.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mail.txt; sourceTree = \"<group>\"; };\n\t\t9872E2F217EBA5A9000385EC /* RVUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVUserDefaults.h; sourceTree = \"<group>\"; };\n\t\t9872E2F317EBA5A9000385EC /* RVUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVUserDefaults.m; sourceTree = \"<group>\"; };\n\t\t9872E2F917EDF2BB000385EC /* RVTutorialPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVTutorialPage.h; sourceTree = \"<group>\"; };\n\t\t9872E2FA17EDF2BB000385EC /* RVTutorialPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVTutorialPage.m; sourceTree = \"<group>\"; };\n\t\t9872E2FC17EDF37D000385EC /* RVTutorialViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVTutorialViewController.h; sourceTree = \"<group>\"; };\n\t\t9872E2FD17EDF37D000385EC /* RVTutorialViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVTutorialViewController.m; sourceTree = \"<group>\"; };\n\t\t9872E2FE17EDF37D000385EC /* RVTutorialViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVTutorialViewController.xib; sourceTree = \"<group>\"; };\n\t\t9872E30117EF144C000385EC /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; };\n\t\t9872E30317EF1470000385EC /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };\n\t\t9872E30517EF159D000385EC /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };\n\t\t9873945117C200910067FED5 /* RVSprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVSprite.h; sourceTree = \"<group>\"; };\n\t\t9873945217C200910067FED5 /* RVSprite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVSprite.m; sourceTree = \"<group>\"; };\n\t\t9873945517C200B40067FED5 /* RVLineSprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVLineSprite.h; sourceTree = \"<group>\"; };\n\t\t9873945617C200B40067FED5 /* RVLineSprite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVLineSprite.m; sourceTree = \"<group>\"; };\n\t\t9873945817C200FC0067FED5 /* RVPointSprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVPointSprite.h; sourceTree = \"<group>\"; };\n\t\t9873945917C200FC0067FED5 /* RVPointSprite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVPointSprite.m; sourceTree = \"<group>\"; };\n\t\t9873945B17C400BB0067FED5 /* RVModelsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelsViewController.h; sourceTree = \"<group>\"; };\n\t\t9873945C17C400BB0067FED5 /* RVModelsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelsViewController.m; sourceTree = \"<group>\"; };\n\t\t9873945D17C400BB0067FED5 /* RVModelsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVModelsViewController.xib; sourceTree = \"<group>\"; };\n\t\t9873946017C400D30067FED5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Revolved/Images.xcassets; sourceTree = SOURCE_ROOT; };\n\t\t9873946417C405130067FED5 /* RVPictureViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVPictureViewController.h; sourceTree = \"<group>\"; };\n\t\t9873946517C405130067FED5 /* RVPictureViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVPictureViewController.m; sourceTree = \"<group>\"; };\n\t\t9873946617C405130067FED5 /* RVPictureViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVPictureViewController.xib; sourceTree = \"<group>\"; };\n\t\t9873946C17C53F0E0067FED5 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };\n\t\t9873946E17C540680067FED5 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };\n\t\t9873947117C559790067FED5 /* RVOpenGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVOpenGLView.h; sourceTree = \"<group>\"; };\n\t\t9873947217C559790067FED5 /* RVOpenGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVOpenGLView.m; sourceTree = \"<group>\"; };\n\t\t9873947417C562050067FED5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };\n\t\t988180C417F2361200C0E6BD /* MFMailComposeViewController+SendIfPossible.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"MFMailComposeViewController+SendIfPossible.h\"; sourceTree = \"<group>\"; };\n\t\t988180C517F2361200C0E6BD /* MFMailComposeViewController+SendIfPossible.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"MFMailComposeViewController+SendIfPossible.m\"; sourceTree = \"<group>\"; };\n\t\t988180C717F385E700C0E6BD /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };\n\t\t98A3451717B6CAD500D0C82F /* RVPointMeshController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVPointMeshController.h; sourceTree = \"<group>\"; };\n\t\t98A3451817B6CAD500D0C82F /* RVPointMeshController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVPointMeshController.m; sourceTree = \"<group>\"; };\n\t\t98A3451A17B6CAE700D0C82F /* RVMeshController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVMeshController.h; sourceTree = \"<group>\"; };\n\t\t98A3451B17B6CAE700D0C82F /* RVMeshController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVMeshController.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98A3451D17B6CB2800D0C82F /* RVMeshController_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RVMeshController_Private.h; sourceTree = \"<group>\"; };\n\t\t98A3451E17B6E4D900D0C82F /* SegmentEnd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SegmentEnd.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98A3451F17B7A16300D0C82F /* RVSegmentConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVSegmentConnection.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98A3452017B7A16300D0C82F /* RVSegmentConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVSegmentConnection.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98A3452217B7AD2900D0C82F /* RVGuideline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVGuideline.h; sourceTree = \"<group>\"; };\n\t\t98A3452317B7AD2900D0C82F /* RVGuideline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVGuideline.m; sourceTree = \"<group>\"; };\n\t\t98A9800317E8FCD500F09CFD /* RVModelButtonsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelButtonsView.h; sourceTree = \"<group>\"; };\n\t\t98A9800417E8FCD500F09CFD /* RVModelButtonsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelButtonsView.m; sourceTree = \"<group>\"; };\n\t\t98A9800617E8FCDF00F09CFD /* RVModelButtonsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVModelButtonsView.xib; sourceTree = \"<group>\"; };\n\t\t98A9800817E8FD9500F09CFD /* RVPreviewViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVPreviewViewController.h; sourceTree = \"<group>\"; };\n\t\t98A9800917E8FD9500F09CFD /* RVPreviewViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVPreviewViewController.m; sourceTree = \"<group>\"; };\n\t\t98A9800A17E8FD9500F09CFD /* RVPreviewViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVPreviewViewController.xib; sourceTree = \"<group>\"; };\n\t\t98ADF00117FCB44200D58007 /* RVSelectTutorialPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVSelectTutorialPage.h; sourceTree = \"<group>\"; };\n\t\t98ADF00217FCB44200D58007 /* RVSelectTutorialPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVSelectTutorialPage.m; sourceTree = \"<group>\"; };\n\t\t98ADF00417FCB44900D58007 /* RVSelectTutorialPage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVSelectTutorialPage.xib; sourceTree = \"<group>\"; };\n\t\t98ADF00E17FCBE7000D58007 /* RVPassForwardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVPassForwardView.h; sourceTree = \"<group>\"; };\n\t\t98ADF00F17FCBE7000D58007 /* RVPassForwardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVPassForwardView.m; sourceTree = \"<group>\"; };\n\t\t98ADF01917FDF85C00D58007 /* RVFinishTutorialPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVFinishTutorialPage.h; sourceTree = \"<group>\"; };\n\t\t98ADF01A17FDF85C00D58007 /* RVFinishTutorialPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVFinishTutorialPage.m; sourceTree = \"<group>\"; };\n\t\t98ADF01C17FDF86200D58007 /* RVFinishTutorialPage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVFinishTutorialPage.xib; sourceTree = \"<group>\"; };\n\t\t98B5C18617D5343000889553 /* RVAxisMeshController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVAxisMeshController.h; sourceTree = \"<group>\"; };\n\t\t98B5C18717D5343000889553 /* RVAxisMeshController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVAxisMeshController.m; sourceTree = \"<group>\"; };\n\t\t98B5C18917D5346F00889553 /* AxisVertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AxisVertex.h; sourceTree = \"<group>\"; };\n\t\t98B8E48A17FB3ECD002F8DDB /* RVSegmentsTutorialPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVSegmentsTutorialPage.h; sourceTree = \"<group>\"; };\n\t\t98B8E48B17FB3ECD002F8DDB /* RVSegmentsTutorialPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVSegmentsTutorialPage.m; sourceTree = \"<group>\"; };\n\t\t98B8E48D17FB3EDE002F8DDB /* RVSegmentsTutorialPage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVSegmentsTutorialPage.xib; sourceTree = \"<group>\"; };\n\t\t98B8E49717FB5233002F8DDB /* RVDrawingTutorialPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVDrawingTutorialPage.h; sourceTree = \"<group>\"; };\n\t\t98B8E49817FB5233002F8DDB /* RVDrawingTutorialPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVDrawingTutorialPage.m; sourceTree = \"<group>\"; };\n\t\t98B8E49A17FB5249002F8DDB /* RVDrawingTutorialPage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVDrawingTutorialPage.xib; sourceTree = \"<group>\"; };\n\t\t98B8E4A617FB5FA1002F8DDB /* RVRevolvedTutorialPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVRevolvedTutorialPage.h; sourceTree = \"<group>\"; };\n\t\t98B8E4A717FB5FA1002F8DDB /* RVRevolvedTutorialPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVRevolvedTutorialPage.m; sourceTree = \"<group>\"; };\n\t\t98B8E4A917FB5FAC002F8DDB /* RVRevolvedTutorialPage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVRevolvedTutorialPage.xib; sourceTree = \"<group>\"; };\n\t\t98B8E4AB17FB695F002F8DDB /* RVTutorialLineImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVTutorialLineImageView.h; sourceTree = \"<group>\"; };\n\t\t98B8E4AC17FB695F002F8DDB /* RVTutorialLineImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVTutorialLineImageView.m; sourceTree = \"<group>\"; };\n\t\t98B8E4B417FB757A002F8DDB /* RVRevolvedTutorialPageSolid.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVRevolvedTutorialPageSolid.xib; sourceTree = \"<group>\"; };\n\t\t98B8E4C017FC87BE002F8DDB /* RVBendTutorialPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVBendTutorialPage.h; sourceTree = \"<group>\"; };\n\t\t98B8E4C117FC87BE002F8DDB /* RVBendTutorialPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVBendTutorialPage.m; sourceTree = \"<group>\"; };\n\t\t98B8E4C317FC87C4002F8DDB /* RVBendTutorialPage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVBendTutorialPage.xib; sourceTree = \"<group>\"; };\n\t\t98B8E4C517FCB2BD002F8DDB /* RVStartTutorialPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVStartTutorialPage.h; sourceTree = \"<group>\"; };\n\t\t98B8E4C617FCB2BD002F8DDB /* RVStartTutorialPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVStartTutorialPage.m; sourceTree = \"<group>\"; };\n\t\t98B8E4C817FCB2C3002F8DDB /* RVStartTutorialPage.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVStartTutorialPage.xib; sourceTree = \"<group>\"; };\n\t\t98C5FE9217B2B56800022331 /* RVDrawViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVDrawViewController.h; sourceTree = \"<group>\"; };\n\t\t98C5FE9317B2B56800022331 /* RVDrawViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVDrawViewController.m; sourceTree = \"<group>\"; };\n\t\t98C5FE9617B2B96100022331 /* RVModelViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RVModelViewController.xib; sourceTree = \"<group>\"; };\n\t\t98C5FE9D17B2BC9D00022331 /* RVSpaceConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVSpaceConverter.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98C5FE9E17B2BC9D00022331 /* RVSpaceConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVSpaceConverter.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98C5FEA017B2CA0300022331 /* RVLineMeshController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVLineMeshController.h; sourceTree = \"<group>\"; };\n\t\t98C5FEA117B2CA0300022331 /* RVLineMeshController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVLineMeshController.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98C5FEA317B2CA3300022331 /* LineVertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LineVertex.h; sourceTree = \"<group>\"; };\n\t\t98C5FEA417B2D8AC00022331 /* RVLineShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVLineShader.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98C5FEA517B2D8AC00022331 /* RVLineShader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVLineShader.m; sourceTree = \"<group>\"; };\n\t\t98C5FEA717B2D93700022331 /* RVLineShader.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = RVLineShader.fsh; sourceTree = \"<group>\"; };\n\t\t98C5FEA817B2D93700022331 /* RVLineShader.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = RVLineShader.vsh; sourceTree = \"<group>\"; };\n\t\t98C5FEAB17B2EFCD00022331 /* DrawGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = DrawGestureRecognizer.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98C5FEAC17B2EFCD00022331 /* DrawGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DrawGestureRecognizer.m; sourceTree = \"<group>\"; };\n\t\t98C5FEAE17B6591600022331 /* Geometry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Geometry.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98C5FEB117B65EE400022331 /* RVDrawController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVDrawController.h; sourceTree = \"<group>\"; };\n\t\t98C5FEB217B65EE400022331 /* RVDrawController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVDrawController.m; sourceTree = \"<group>\"; };\n\t\t98C5FEB717B66BEB00022331 /* RVPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVPoint.h; sourceTree = \"<group>\"; };\n\t\t98C5FEB817B66BEB00022331 /* RVPoint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVPoint.m; sourceTree = \"<group>\"; };\n\t\t98CD44D818303F0D004D1986 /* RVExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVExporter.h; sourceTree = \"<group>\"; };\n\t\t98CD44D918303F0D004D1986 /* RVExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVExporter.m; sourceTree = \"<group>\"; };\n\t\t98CD44DB18304056004D1986 /* RVSTLExporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVSTLExporter.h; sourceTree = \"<group>\"; };\n\t\t98CD44DC18304056004D1986 /* RVSTLExporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVSTLExporter.m; sourceTree = \"<group>\"; };\n\t\t98D6BA0417F0EF2100BFEDB4 /* RVCreditsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVCreditsViewController.h; sourceTree = \"<group>\"; };\n\t\t98D6BA0517F0EF2200BFEDB4 /* RVCreditsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVCreditsViewController.m; sourceTree = \"<group>\"; };\n\t\t98D6BA0617F0EF2200BFEDB4 /* RVCreditsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RVCreditsViewController.xib; sourceTree = \"<group>\"; };\n\t\t98EAA22E1804AC6800D0B527 /* RVTutorialScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVTutorialScrollView.h; sourceTree = \"<group>\"; };\n\t\t98EAA22F1804AC6800D0B527 /* RVTutorialScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVTutorialScrollView.m; sourceTree = \"<group>\"; };\n\t\t98ED502E17C7CCDA00E5FE1F /* RVModelSerializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelSerializer.h; sourceTree = \"<group>\"; };\n\t\t98ED502F17C7CCDA00E5FE1F /* RVModelSerializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelSerializer.m; sourceTree = \"<group>\"; };\n\t\t98ED507A17C7CF6800E5FE1F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };\n\t\t98ED508017C7CF6800E5FE1F /* Revolved Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = \"Revolved Tests-Info.plist\"; sourceTree = \"<group>\"; };\n\t\t98ED508217C7CF6800E5FE1F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = \"<group>\"; };\n\t\t98ED508617C7CF6800E5FE1F /* Revolved Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"Revolved Tests-Prefix.pch\"; sourceTree = \"<group>\"; };\n\t\t98ED508D17C7D07000E5FE1F /* RVSerializerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVSerializerTests.m; sourceTree = \"<group>\"; };\n\t\t98FADE5117EB118E00E1DFE0 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; };\n\t\t98FB7E6817AD75D3000262F2 /* Revolved.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Revolved.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t98FB7E6B17AD75D3000262F2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };\n\t\t98FB7E6D17AD75D3000262F2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };\n\t\t98FB7E6F17AD75D3000262F2 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };\n\t\t98FB7E7317AD75D3000262F2 /* Revolved-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = \"Revolved-Info.plist\"; sourceTree = \"<group>\"; };\n\t\t98FB7E7517AD75D3000262F2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = \"<group>\"; };\n\t\t98FB7E7717AD75D3000262F2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98FB7E7917AD75D3000262F2 /* Revolved-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"Revolved-Prefix.pch\"; sourceTree = \"<group>\"; };\n\t\t98FB7E7A17AD75D3000262F2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t98FB7E7B17AD75D3000262F2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AppDelegate.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98FB7E8F17AD76BF000262F2 /* RVSegment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVSegment.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98FB7E9017AD76BF000262F2 /* RVSegment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVSegment.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98FB7E9817AD785A000262F2 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; };\n\t\t98FB7E9B17AD78F0000262F2 /* RVModelViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RVModelViewController.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98FB7E9C17AD78F0000262F2 /* RVModelViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = RVModelViewController.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };\n\t\t98FB7E9F17AD79A8000262F2 /* Color.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Color.h; sourceTree = \"<group>\"; };\n\t\t98FB7EAC17AD7EF7000262F2 /* CameraController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CameraController.h; sourceTree = \"<group>\"; };\n\t\t98FB7EAD17AD7EF7000262F2 /* CameraController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraController.m; sourceTree = \"<group>\"; };\n\t\t98FB7EAF17AD7FD4000262F2 /* Camera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Camera.h; sourceTree = \"<group>\"; };\n\t\t98FB7EB017AD7FD4000262F2 /* Camera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Camera.m; sourceTree = \"<group>\"; };\n\t\t98FB7EB217AD82CB000262F2 /* Vertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Vertex.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98FB7EB617AD8480000262F2 /* RVModelMeshController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelMeshController.h; sourceTree = \"<group>\"; };\n\t\t98FB7EB717AD8480000262F2 /* RVModelMeshController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelMeshController.m; sourceTree = \"<group>\"; };\n\t\t98FB7EB817AD8480000262F2 /* Renderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Renderer.h; sourceTree = \"<group>\"; };\n\t\t98FB7EB917AD8480000262F2 /* Renderer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Renderer.m; sourceTree = \"<group>\"; };\n\t\t98FB7EBE17AD864A000262F2 /* BCShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BCShader.h; sourceTree = \"<group>\"; };\n\t\t98FB7EBF17AD864A000262F2 /* BCShader_SubclassHooks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BCShader_SubclassHooks.h; sourceTree = \"<group>\"; };\n\t\t98FB7EC017AD864A000262F2 /* BCShader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BCShader.m; sourceTree = \"<group>\"; };\n\t\t98FB7EC117AD864A000262F2 /* RVModelShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVModelShader.h; sourceTree = \"<group>\"; };\n\t\t98FB7EC217AD864A000262F2 /* RVModelShader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVModelShader.m; sourceTree = \"<group>\"; };\n\t\t98FB7EC317AD864A000262F2 /* RVModelShader.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = RVModelShader.vsh; sourceTree = \"<group>\"; };\n\t\t98FB7EC417AD864A000262F2 /* RVModelShader.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = RVModelShader.fsh; sourceTree = \"<group>\"; };\n\t\t98FB7EC917B0293D000262F2 /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Constants.h; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };\n\t\t98FB7ECD17B03B65000262F2 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };\n\t\t98FDDB36180176A000F16136 /* noise.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = noise.png; sourceTree = \"<group>\"; };\n\t\t98FDDB38180176AD00F16136 /* sprites.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sprites.png; sourceTree = \"<group>\"; };\n\t\t98FDDB3A1801930F00F16136 /* RVColorPickerButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RVColorPickerButton.h; sourceTree = \"<group>\"; };\n\t\t98FDDB3B1801930F00F16136 /* RVColorPickerButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RVColorPickerButton.m; sourceTree = \"<group>\"; };\n\t\t98FDDB3D1801E4A600F16136 /* model1.rvlvd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = model1.rvlvd; sourceTree = \"<group>\"; };\n\t\t98FDDB3E1801E4A600F16136 /* model2.rvlvd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = model2.rvlvd; sourceTree = \"<group>\"; };\n\t\t98FDDB3F1801E4A600F16136 /* model3.rvlvd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = model3.rvlvd; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t98FB7E6517AD75D3000262F2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t9832A66E186E0EE2003501AE /* libz.dylib in Frameworks */,\n\t\t\t\t988180C817F385E700C0E6BD /* StoreKit.framework in Frameworks */,\n\t\t\t\t9872E30617EF159D000385EC /* AssetsLibrary.framework in Frameworks */,\n\t\t\t\t9872E30417EF1470000385EC /* Twitter.framework in Frameworks */,\n\t\t\t\t9872E30217EF144C000385EC /* Social.framework in Frameworks */,\n\t\t\t\t98FADE5217EB118E00E1DFE0 /* MessageUI.framework in Frameworks */,\n\t\t\t\t9873947517C562050067FED5 /* QuartzCore.framework in Frameworks */,\n\t\t\t\t9873946F17C540680067FED5 /* CoreVideo.framework in Frameworks */,\n\t\t\t\t9873946D17C53F0E0067FED5 /* AVFoundation.framework in Frameworks */,\n\t\t\t\t98FB7ECE17B03B65000262F2 /* OpenGLES.framework in Frameworks */,\n\t\t\t\t98FB7E9917AD785A000262F2 /* GLKit.framework in Frameworks */,\n\t\t\t\t98FB7E6C17AD75D3000262F2 /* UIKit.framework in Frameworks */,\n\t\t\t\t98FB7E6E17AD75D3000262F2 /* Foundation.framework in Frameworks */,\n\t\t\t\t98FB7E7017AD75D3000262F2 /* CoreGraphics.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t9832A667186E0E65003501AE /* SSZip */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9832A66F186E0F98003501AE /* minizip */,\n\t\t\t\t9832A669186E0E72003501AE /* SSZipArchive.h */,\n\t\t\t\t9832A66A186E0E72003501AE /* SSZipArchive.m */,\n\t\t\t);\n\t\t\tname = SSZip;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9832A66F186E0F98003501AE /* minizip */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9832A670186E0F98003501AE /* crypt.h */,\n\t\t\t\t9832A671186E0F98003501AE /* ioapi.c */,\n\t\t\t\t9832A672186E0F98003501AE /* ioapi.h */,\n\t\t\t\t9832A673186E0F98003501AE /* mztools.c */,\n\t\t\t\t9832A674186E0F98003501AE /* mztools.h */,\n\t\t\t\t9832A675186E0F98003501AE /* unzip.c */,\n\t\t\t\t9832A676186E0F98003501AE /* unzip.h */,\n\t\t\t\t9832A677186E0F98003501AE /* zip.c */,\n\t\t\t\t9832A678186E0F98003501AE /* zip.h */,\n\t\t\t);\n\t\t\tpath = minizip;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9852517F17BD1F6F00B348F4 /* Points */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9852518017BD1F8400B348F4 /* RVAnchorPoint.h */,\n\t\t\t\t9852518117BD1F8400B348F4 /* RVAnchorPoint.m */,\n\t\t\t\t9852518317BD1F9300B348F4 /* RVControlPoint.h */,\n\t\t\t\t9852518417BD1F9300B348F4 /* RVControlPoint.m */,\n\t\t\t\t9852518617BD1F9C00B348F4 /* RVEndPoint.h */,\n\t\t\t\t9852518717BD1F9C00B348F4 /* RVEndPoint.m */,\n\t\t\t);\n\t\t\tname = Points;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t985E10DE17CA687500BE4C28 /* Animation */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t985E10DF17CA688400BE4C28 /* RVAnimator.h */,\n\t\t\t\t985E10E017CA688400BE4C28 /* RVAnimator.m */,\n\t\t\t\t985E10E317CA691100BE4C28 /* RVAnimation.h */,\n\t\t\t\t985E10EC17CA6B4E00BE4C28 /* RVAnimation_Private.h */,\n\t\t\t\t985E10E417CA691100BE4C28 /* RVAnimation.m */,\n\t\t\t\t985E10E617CA6B1600BE4C28 /* RVFloatAnimation.h */,\n\t\t\t\t985E10E717CA6B1600BE4C28 /* RVFloatAnimation.m */,\n\t\t\t\t985E10E917CA6B2200BE4C28 /* RVVectorAnimation.h */,\n\t\t\t\t985E10EA17CA6B2200BE4C28 /* RVVectorAnimation.m */,\n\t\t\t\t981395A717DD144700C17CB1 /* RVQuaternionAnimation.h */,\n\t\t\t\t981395A817DD144700C17CB1 /* RVQuaternionAnimation.m */,\n\t\t\t);\n\t\t\tname = Animation;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9861247F17C7FA300051C092 /* Misc */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98ADF00E17FCBE7000D58007 /* RVPassForwardView.h */,\n\t\t\t\t98ADF00F17FCBE7000D58007 /* RVPassForwardView.m */,\n\t\t\t\t98C5FEAB17B2EFCD00022331 /* DrawGestureRecognizer.h */,\n\t\t\t\t98C5FEAC17B2EFCD00022331 /* DrawGestureRecognizer.m */,\n\t\t\t\t9861248C17C802060051C092 /* UIColor+RevolvedColors.h */,\n\t\t\t\t9861248D17C802060051C092 /* UIColor+RevolvedColors.m */,\n\t\t\t\t98294FAA17CFD852003CAE5F /* NSArray+Functional.h */,\n\t\t\t\t98294FAB17CFD852003CAE5F /* NSArray+Functional.m */,\n\t\t\t\t98294FAE17D354A1003CAE5F /* NSError+RevolvedErrors.h */,\n\t\t\t\t98294FAF17D354A1003CAE5F /* NSError+RevolvedErrors.m */,\n\t\t\t\t985E10DA17CA54F300BE4C28 /* NSMapTable+BlockEnumeration.h */,\n\t\t\t\t985E10DB17CA54F300BE4C28 /* NSMapTable+BlockEnumeration.m */,\n\t\t\t\t9850E0AA17F74376006B8ACD /* UIView+RotationAnimation.h */,\n\t\t\t\t9850E0AB17F74376006B8ACD /* UIView+RotationAnimation.m */,\n\t\t\t\t9859CA1117E625AC000E539F /* NSMutableArray+MoveObject.h */,\n\t\t\t\t9859CA1217E625AC000E539F /* NSMutableArray+MoveObject.m */,\n\t\t\t\t9859CA1417E627BA000E539F /* NSMutableOrderedSet+MoveObject.h */,\n\t\t\t\t9859CA1517E627BA000E539F /* NSMutableOrderedSet+MoveObject.m */,\n\t\t\t\t988180C417F2361200C0E6BD /* MFMailComposeViewController+SendIfPossible.h */,\n\t\t\t\t988180C517F2361200C0E6BD /* MFMailComposeViewController+SendIfPossible.m */,\n\t\t\t);\n\t\t\tname = Misc;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9861248017C7FCB10051C092 /* Model Handling */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9861247C17C7FA290051C092 /* RVModelManager.h */,\n\t\t\t\t9861247D17C7FA290051C092 /* RVModelManager.m */,\n\t\t\t\t98294FB117D361C6003CAE5F /* RVModelMetadata.h */,\n\t\t\t\t98294FB217D361C6003CAE5F /* RVModelMetadata.m */,\n\t\t\t\t9861248117C7FCC80051C092 /* RVModel.h */,\n\t\t\t\t9861248217C7FCC80051C092 /* RVModel.m */,\n\t\t\t);\n\t\t\tname = \"Model Handling\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9861248417C801160051C092 /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9861248517C8012D0051C092 /* RVModelCell.h */,\n\t\t\t\t9861248617C8012D0051C092 /* RVModelCell.m */,\n\t\t\t\t980CC35A17F0AEAE0057D5AD /* RVSettingsButtonsView.h */,\n\t\t\t\t980CC35B17F0AEAE0057D5AD /* RVSettingsButtonsView.m */,\n\t\t\t\t980CC35D17F0AECD0057D5AD /* RVSettingsButtonsView.xib */,\n\t\t\t\t98A9800317E8FCD500F09CFD /* RVModelButtonsView.h */,\n\t\t\t\t98A9800417E8FCD500F09CFD /* RVModelButtonsView.m */,\n\t\t\t\t98A9800617E8FCDF00F09CFD /* RVModelButtonsView.xib */,\n\t\t\t\t9859CA1C17E651B4000E539F /* RVAddProgressView.h */,\n\t\t\t\t9859CA1D17E651B4000E539F /* RVAddProgressView.m */,\n\t\t\t);\n\t\t\tname = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9872E2F517EDF275000385EC /* Tutorial */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9872E2F917EDF2BB000385EC /* RVTutorialPage.h */,\n\t\t\t\t9872E2FA17EDF2BB000385EC /* RVTutorialPage.m */,\n\t\t\t\t98EAA22E1804AC6800D0B527 /* RVTutorialScrollView.h */,\n\t\t\t\t98EAA22F1804AC6800D0B527 /* RVTutorialScrollView.m */,\n\t\t\t\t98B8E4C517FCB2BD002F8DDB /* RVStartTutorialPage.h */,\n\t\t\t\t98B8E4C617FCB2BD002F8DDB /* RVStartTutorialPage.m */,\n\t\t\t\t98B8E4C817FCB2C3002F8DDB /* RVStartTutorialPage.xib */,\n\t\t\t\t98B8E48A17FB3ECD002F8DDB /* RVSegmentsTutorialPage.h */,\n\t\t\t\t98B8E48B17FB3ECD002F8DDB /* RVSegmentsTutorialPage.m */,\n\t\t\t\t98B8E48D17FB3EDE002F8DDB /* RVSegmentsTutorialPage.xib */,\n\t\t\t\t98B8E49717FB5233002F8DDB /* RVDrawingTutorialPage.h */,\n\t\t\t\t98B8E49817FB5233002F8DDB /* RVDrawingTutorialPage.m */,\n\t\t\t\t98B8E49A17FB5249002F8DDB /* RVDrawingTutorialPage.xib */,\n\t\t\t\t98B8E4A617FB5FA1002F8DDB /* RVRevolvedTutorialPage.h */,\n\t\t\t\t98B8E4A717FB5FA1002F8DDB /* RVRevolvedTutorialPage.m */,\n\t\t\t\t98B8E4A917FB5FAC002F8DDB /* RVRevolvedTutorialPage.xib */,\n\t\t\t\t98B8E4B417FB757A002F8DDB /* RVRevolvedTutorialPageSolid.xib */,\n\t\t\t\t98ADF00117FCB44200D58007 /* RVSelectTutorialPage.h */,\n\t\t\t\t98ADF00217FCB44200D58007 /* RVSelectTutorialPage.m */,\n\t\t\t\t98ADF00417FCB44900D58007 /* RVSelectTutorialPage.xib */,\n\t\t\t\t98B8E4C017FC87BE002F8DDB /* RVBendTutorialPage.h */,\n\t\t\t\t98B8E4C117FC87BE002F8DDB /* RVBendTutorialPage.m */,\n\t\t\t\t98B8E4C317FC87C4002F8DDB /* RVBendTutorialPage.xib */,\n\t\t\t\t98ADF01917FDF85C00D58007 /* RVFinishTutorialPage.h */,\n\t\t\t\t98ADF01A17FDF85C00D58007 /* RVFinishTutorialPage.m */,\n\t\t\t\t98ADF01C17FDF86200D58007 /* RVFinishTutorialPage.xib */,\n\t\t\t\t9872E2FC17EDF37D000385EC /* RVTutorialViewController.h */,\n\t\t\t\t9872E2FD17EDF37D000385EC /* RVTutorialViewController.m */,\n\t\t\t\t9872E2FE17EDF37D000385EC /* RVTutorialViewController.xib */,\n\t\t\t\t98B8E4AB17FB695F002F8DDB /* RVTutorialLineImageView.h */,\n\t\t\t\t98B8E4AC17FB695F002F8DDB /* RVTutorialLineImageView.m */,\n\t\t\t);\n\t\t\tname = Tutorial;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9873945417C200A80067FED5 /* Sprites */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9873945117C200910067FED5 /* RVSprite.h */,\n\t\t\t\t9873945217C200910067FED5 /* RVSprite.m */,\n\t\t\t\t9873945517C200B40067FED5 /* RVLineSprite.h */,\n\t\t\t\t9873945617C200B40067FED5 /* RVLineSprite.m */,\n\t\t\t\t9873945817C200FC0067FED5 /* RVPointSprite.h */,\n\t\t\t\t9873945917C200FC0067FED5 /* RVPointSprite.m */,\n\t\t\t\t985E10D717C946E600BE4C28 /* RVModelSprite.h */,\n\t\t\t\t985E10D817C946E600BE4C28 /* RVModelSprite.m */,\n\t\t\t\t98557F6517D7C6190062472B /* RVGuidelineDotSprite.h */,\n\t\t\t\t98557F6617D7C6190062472B /* RVGuidelineDotSprite.m */,\n\t\t\t\t98557F6217D6758D0062472B /* RVAxisSprite.h */,\n\t\t\t\t98557F6317D6758D0062472B /* RVAxisSprite.m */,\n\t\t\t);\n\t\t\tname = Sprites;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98C5FE9117B2B55000022331 /* Drawing */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98C5FEB117B65EE400022331 /* RVDrawController.h */,\n\t\t\t\t98C5FEB217B65EE400022331 /* RVDrawController.m */,\n\t\t\t\t98C5FEA017B2CA0300022331 /* RVLineMeshController.h */,\n\t\t\t\t98C5FEA117B2CA0300022331 /* RVLineMeshController.m */,\n\t\t\t\t98B5C18617D5343000889553 /* RVAxisMeshController.h */,\n\t\t\t\t98B5C18717D5343000889553 /* RVAxisMeshController.m */,\n\t\t\t\t98A3451717B6CAD500D0C82F /* RVPointMeshController.h */,\n\t\t\t\t98A3451817B6CAD500D0C82F /* RVPointMeshController.m */,\n\t\t\t\t98FB7EB617AD8480000262F2 /* RVModelMeshController.h */,\n\t\t\t\t98FB7EB717AD8480000262F2 /* RVModelMeshController.m */,\n\t\t\t\t98557F6817D7CB300062472B /* RVGuidlineDotMeshController.h */,\n\t\t\t\t98557F6917D7CB300062472B /* RVGuidlineDotMeshController.m */,\n\t\t\t\t98C5FE9D17B2BC9D00022331 /* RVSpaceConverter.h */,\n\t\t\t\t98C5FE9E17B2BC9D00022331 /* RVSpaceConverter.m */,\n\t\t\t\t98C5FEA317B2CA3300022331 /* LineVertex.h */,\n\t\t\t\t9852518917BD2E3700B348F4 /* PointVertex.h */,\n\t\t\t\t98B5C18917D5346F00889553 /* AxisVertex.h */,\n\t\t\t\t9852517B17BC09C600B348F4 /* RVColorPicker.h */,\n\t\t\t\t9852517C17BC09C600B348F4 /* RVColorPicker.m */,\n\t\t\t\t98FDDB3A1801930F00F16136 /* RVColorPickerButton.h */,\n\t\t\t\t98FDDB3B1801930F00F16136 /* RVColorPickerButton.m */,\n\t\t\t\t9852519317BEC58200B348F4 /* RVDeleteView.h */,\n\t\t\t\t9852519417BEC58200B348F4 /* RVDeleteView.m */,\n\t\t\t\t98475ACC17C0D232002FD2AB /* RVColorProvider.h */,\n\t\t\t\t98475ACD17C0D232002FD2AB /* RVColorProvider.m */,\n\t\t\t);\n\t\t\tname = Drawing;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98CD44D718303F00004D1986 /* Exporters */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98CD44D818303F0D004D1986 /* RVExporter.h */,\n\t\t\t\t98CD44D918303F0D004D1986 /* RVExporter.m */,\n\t\t\t\t98CD44DB18304056004D1986 /* RVSTLExporter.h */,\n\t\t\t\t98CD44DC18304056004D1986 /* RVSTLExporter.m */,\n\t\t\t\t986C0C3D183816F300F8F51D /* RVOBJExporter.h */,\n\t\t\t\t986C0C3E183816F300F8F51D /* RVOBJExporter.m */,\n\t\t\t);\n\t\t\tname = Exporters;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98ED507E17C7CF6800E5FE1F /* Revolved Tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9861247A17C7F59E0051C092 /* RVConnectionTests.m */,\n\t\t\t\t98ED508D17C7D07000E5FE1F /* RVSerializerTests.m */,\n\t\t\t\t98ED507F17C7CF6800E5FE1F /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = \"Revolved Tests\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98ED507F17C7CF6800E5FE1F /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98ED508017C7CF6800E5FE1F /* Revolved Tests-Info.plist */,\n\t\t\t\t98ED508117C7CF6800E5FE1F /* InfoPlist.strings */,\n\t\t\t\t98ED508617C7CF6800E5FE1F /* Revolved Tests-Prefix.pch */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7E5F17AD75D3000262F2 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98FB7E7117AD75D3000262F2 /* Revolved */,\n\t\t\t\t98ED507E17C7CF6800E5FE1F /* Revolved Tests */,\n\t\t\t\t98FB7E6A17AD75D3000262F2 /* Frameworks */,\n\t\t\t\t98FB7E6917AD75D3000262F2 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7E6917AD75D3000262F2 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98FB7E6817AD75D3000262F2 /* Revolved.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7E6A17AD75D3000262F2 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9832A66D186E0EE2003501AE /* libz.dylib */,\n\t\t\t\t988180C717F385E700C0E6BD /* StoreKit.framework */,\n\t\t\t\t9872E30517EF159D000385EC /* AssetsLibrary.framework */,\n\t\t\t\t9872E30317EF1470000385EC /* Twitter.framework */,\n\t\t\t\t9872E30117EF144C000385EC /* Social.framework */,\n\t\t\t\t98FADE5117EB118E00E1DFE0 /* MessageUI.framework */,\n\t\t\t\t9873947417C562050067FED5 /* QuartzCore.framework */,\n\t\t\t\t9873946E17C540680067FED5 /* CoreVideo.framework */,\n\t\t\t\t9873946C17C53F0E0067FED5 /* AVFoundation.framework */,\n\t\t\t\t98FB7ECD17B03B65000262F2 /* OpenGLES.framework */,\n\t\t\t\t98FB7E9817AD785A000262F2 /* GLKit.framework */,\n\t\t\t\t98FB7E6B17AD75D3000262F2 /* UIKit.framework */,\n\t\t\t\t98FB7E6D17AD75D3000262F2 /* Foundation.framework */,\n\t\t\t\t98FB7E6F17AD75D3000262F2 /* CoreGraphics.framework */,\n\t\t\t\t98ED507A17C7CF6800E5FE1F /* XCTest.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7E7117AD75D3000262F2 /* Revolved */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98CD44D718303F00004D1986 /* Exporters */,\n\t\t\t\t9872E2F517EDF275000385EC /* Tutorial */,\n\t\t\t\t985E10DE17CA687500BE4C28 /* Animation */,\n\t\t\t\t9861248017C7FCB10051C092 /* Model Handling */,\n\t\t\t\t9861247F17C7FA300051C092 /* Misc */,\n\t\t\t\t9873945417C200A80067FED5 /* Sprites */,\n\t\t\t\t98C5FE9117B2B55000022331 /* Drawing */,\n\t\t\t\t98FB7EBC17AD8610000262F2 /* Rendering */,\n\t\t\t\t9861248417C801160051C092 /* Views */,\n\t\t\t\t98FB7EA817AD7D7C000262F2 /* Preview */,\n\t\t\t\t98FB7E9A17AD78E0000262F2 /* ViewControllers */,\n\t\t\t\t98FB7E9E17AD7999000262F2 /* Model */,\n\t\t\t\t98FB7E7A17AD75D3000262F2 /* AppDelegate.h */,\n\t\t\t\t98FB7E7B17AD75D3000262F2 /* AppDelegate.m */,\n\t\t\t\t9872E2F217EBA5A9000385EC /* RVUserDefaults.h */,\n\t\t\t\t9872E2F317EBA5A9000385EC /* RVUserDefaults.m */,\n\t\t\t\t98FB7E7217AD75D3000262F2 /* Supporting Files */,\n\t\t\t\t9873946017C400D30067FED5 /* Images.xcassets */,\n\t\t\t);\n\t\t\tname = Revolved;\n\t\t\tpath = Revolved;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7E7217AD75D3000262F2 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9832A667186E0E65003501AE /* SSZip */,\n\t\t\t\t98FDDB3D1801E4A600F16136 /* model1.rvlvd */,\n\t\t\t\t98FDDB3E1801E4A600F16136 /* model2.rvlvd */,\n\t\t\t\t98FDDB3F1801E4A600F16136 /* model3.rvlvd */,\n\t\t\t\t9872E2F017EB17E2000385EC /* mail.txt */,\n\t\t\t\t98FDDB36180176A000F16136 /* noise.png */,\n\t\t\t\t98FDDB38180176AD00F16136 /* sprites.png */,\n\t\t\t\t98FB7E7317AD75D3000262F2 /* Revolved-Info.plist */,\n\t\t\t\t98FB7E7417AD75D3000262F2 /* InfoPlist.strings */,\n\t\t\t\t98FB7E7717AD75D3000262F2 /* main.m */,\n\t\t\t\t98FB7E7917AD75D3000262F2 /* Revolved-Prefix.pch */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7E9A17AD78E0000262F2 /* ViewControllers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98C5FE9217B2B56800022331 /* RVDrawViewController.h */,\n\t\t\t\t98C5FE9317B2B56800022331 /* RVDrawViewController.m */,\n\t\t\t\t985E10EE17CA778C00BE4C28 /* RVDrawViewController.xib */,\n\t\t\t\t98A9800817E8FD9500F09CFD /* RVPreviewViewController.h */,\n\t\t\t\t98A9800917E8FD9500F09CFD /* RVPreviewViewController.m */,\n\t\t\t\t98A9800A17E8FD9500F09CFD /* RVPreviewViewController.xib */,\n\t\t\t\t98D6BA0417F0EF2100BFEDB4 /* RVCreditsViewController.h */,\n\t\t\t\t98D6BA0517F0EF2200BFEDB4 /* RVCreditsViewController.m */,\n\t\t\t\t98D6BA0617F0EF2200BFEDB4 /* RVCreditsViewController.xib */,\n\t\t\t\t98FB7E9B17AD78F0000262F2 /* RVModelViewController.h */,\n\t\t\t\t98FB7E9C17AD78F0000262F2 /* RVModelViewController.m */,\n\t\t\t\t98C5FE9617B2B96100022331 /* RVModelViewController.xib */,\n\t\t\t\t9873945B17C400BB0067FED5 /* RVModelsViewController.h */,\n\t\t\t\t9873945C17C400BB0067FED5 /* RVModelsViewController.m */,\n\t\t\t\t9873945D17C400BB0067FED5 /* RVModelsViewController.xib */,\n\t\t\t\t9873946417C405130067FED5 /* RVPictureViewController.h */,\n\t\t\t\t9873946517C405130067FED5 /* RVPictureViewController.m */,\n\t\t\t\t9873946617C405130067FED5 /* RVPictureViewController.xib */,\n\t\t\t\t9861249217C8DDBB0051C092 /* RVRootViewController.h */,\n\t\t\t\t9861249317C8DDBB0051C092 /* RVRootViewController.m */,\n\t\t\t\t982D8D0117DCDEB6004C273F /* RVRootViewController.xib */,\n\t\t\t\t9832A662186DEB7A003501AE /* RVExportViewController.h */,\n\t\t\t\t9832A663186DEB7A003501AE /* RVExportViewController.m */,\n\t\t\t\t9832A664186DEB7A003501AE /* RVExportViewController.xib */,\n\t\t\t);\n\t\t\tname = ViewControllers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7E9E17AD7999000262F2 /* Model */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9852517F17BD1F6F00B348F4 /* Points */,\n\t\t\t\t98C5FEB717B66BEB00022331 /* RVPoint.h */,\n\t\t\t\t98C5FEB817B66BEB00022331 /* RVPoint.m */,\n\t\t\t\t98FB7E8F17AD76BF000262F2 /* RVSegment.h */,\n\t\t\t\t98FB7E9017AD76BF000262F2 /* RVSegment.m */,\n\t\t\t\t98A3451F17B7A16300D0C82F /* RVSegmentConnection.h */,\n\t\t\t\t98A3452017B7A16300D0C82F /* RVSegmentConnection.m */,\n\t\t\t\t98A3452217B7AD2900D0C82F /* RVGuideline.h */,\n\t\t\t\t98A3452317B7AD2900D0C82F /* RVGuideline.m */,\n\t\t\t\t98ED502E17C7CCDA00E5FE1F /* RVModelSerializer.h */,\n\t\t\t\t98ED502F17C7CCDA00E5FE1F /* RVModelSerializer.m */,\n\t\t\t\t98FB7E9F17AD79A8000262F2 /* Color.h */,\n\t\t\t\t98C5FEAE17B6591600022331 /* Geometry.h */,\n\t\t\t\t98A3451E17B6E4D900D0C82F /* SegmentEnd.h */,\n\t\t\t);\n\t\t\tname = Model;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7EA817AD7D7C000262F2 /* Preview */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98FB7EAC17AD7EF7000262F2 /* CameraController.h */,\n\t\t\t\t98FB7EAD17AD7EF7000262F2 /* CameraController.m */,\n\t\t\t\t98FB7EAF17AD7FD4000262F2 /* Camera.h */,\n\t\t\t\t98FB7EB017AD7FD4000262F2 /* Camera.m */,\n\t\t\t\t98FB7EB817AD8480000262F2 /* Renderer.h */,\n\t\t\t\t98FB7EB917AD8480000262F2 /* Renderer.m */,\n\t\t\t\t98557F6B17DCD26A0062472B /* RVRenderingController.h */,\n\t\t\t\t98557F6C17DCD26A0062472B /* RVRenderingController.m */,\n\t\t\t\t98FB7EB217AD82CB000262F2 /* Vertex.h */,\n\t\t\t\t98FB7EC917B0293D000262F2 /* Constants.h */,\n\t\t\t);\n\t\t\tname = Preview;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7EBC17AD8610000262F2 /* Rendering */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98FB7EBD17AD861D000262F2 /* Shaders */,\n\t\t\t\t98A3451A17B6CAE700D0C82F /* RVMeshController.h */,\n\t\t\t\t98A3451D17B6CB2800D0C82F /* RVMeshController_Private.h */,\n\t\t\t\t98A3451B17B6CAE700D0C82F /* RVMeshController.m */,\n\t\t\t\t9873947117C559790067FED5 /* RVOpenGLView.h */,\n\t\t\t\t9873947217C559790067FED5 /* RVOpenGLView.m */,\n\t\t\t);\n\t\t\tname = Rendering;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7EBD17AD861D000262F2 /* Shaders */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98FB7EBE17AD864A000262F2 /* BCShader.h */,\n\t\t\t\t98FB7EBF17AD864A000262F2 /* BCShader_SubclassHooks.h */,\n\t\t\t\t98FB7EC017AD864A000262F2 /* BCShader.m */,\n\t\t\t\t98FB7EC117AD864A000262F2 /* RVModelShader.h */,\n\t\t\t\t98FB7EC217AD864A000262F2 /* RVModelShader.m */,\n\t\t\t\t98FB7EC317AD864A000262F2 /* RVModelShader.vsh */,\n\t\t\t\t98FB7EC417AD864A000262F2 /* RVModelShader.fsh */,\n\t\t\t\t98294FB917D53157003CAE5F /* RVAxisShader.h */,\n\t\t\t\t98294FBA17D53157003CAE5F /* RVAxisShader.m */,\n\t\t\t\t98294FBC17D5325A003CAE5F /* RVAxisShader.vsh */,\n\t\t\t\t98294FBD17D5325A003CAE5F /* RVAxisShader.fsh */,\n\t\t\t\t98C5FEA417B2D8AC00022331 /* RVLineShader.h */,\n\t\t\t\t98C5FEA517B2D8AC00022331 /* RVLineShader.m */,\n\t\t\t\t98C5FEA817B2D93700022331 /* RVLineShader.vsh */,\n\t\t\t\t98C5FEA717B2D93700022331 /* RVLineShader.fsh */,\n\t\t\t\t9852518C17BD324900B348F4 /* RVPointShader.h */,\n\t\t\t\t9852518D17BD324900B348F4 /* RVPointShader.m */,\n\t\t\t\t9852518F17BD326600B348F4 /* RVPointShader.vsh */,\n\t\t\t\t9852519017BD326600B348F4 /* RVPointShader.fsh */,\n\t\t\t);\n\t\t\tname = Shaders;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t98FB7E6717AD75D3000262F2 /* Revolved */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 98FB7E8B17AD75D3000262F2 /* Build configuration list for PBXNativeTarget \"Revolved\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t98FB7E6417AD75D3000262F2 /* Sources */,\n\t\t\t\t98FB7E6517AD75D3000262F2 /* Frameworks */,\n\t\t\t\t98FB7E6617AD75D3000262F2 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Revolved;\n\t\t\tproductName = Revolved;\n\t\t\tproductReference = 98FB7E6817AD75D3000262F2 /* Revolved.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t98FB7E6017AD75D3000262F2 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tCLASSPREFIX = RV;\n\t\t\t\tLastUpgradeCheck = 0510;\n\t\t\t\tORGANIZATIONNAME = \"Bartosz Ciechanowski\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t98FB7E6717AD75D3000262F2 = {\n\t\t\t\t\t\tDevelopmentTeam = HTQ58ZJ2Z9;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.InAppPurchase = {\n\t\t\t\t\t\t\t\tenabled = 0;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 98FB7E6317AD75D3000262F2 /* Build configuration list for PBXProject \"Revolved\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 98FB7E5F17AD75D3000262F2;\n\t\t\tproductRefGroup = 98FB7E6917AD75D3000262F2 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t98FB7E6717AD75D3000262F2 /* Revolved */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t98FB7E6617AD75D3000262F2 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98B8E4C417FC87C5002F8DDB /* RVBendTutorialPage.xib in Resources */,\n\t\t\t\t98B8E4B517FB757B002F8DDB /* RVRevolvedTutorialPageSolid.xib in Resources */,\n\t\t\t\t98294FBE17D5325A003CAE5F /* RVAxisShader.vsh in Resources */,\n\t\t\t\t98FDDB39180176AD00F16136 /* sprites.png in Resources */,\n\t\t\t\t98294FBF17D5325A003CAE5F /* RVAxisShader.fsh in Resources */,\n\t\t\t\t98A9800717E8FCDF00F09CFD /* RVModelButtonsView.xib in Resources */,\n\t\t\t\t98B8E4AA17FB5FAC002F8DDB /* RVRevolvedTutorialPage.xib in Resources */,\n\t\t\t\t98A9800C17E8FD9500F09CFD /* RVPreviewViewController.xib in Resources */,\n\t\t\t\t98FB7E7617AD75D3000262F2 /* InfoPlist.strings in Resources */,\n\t\t\t\t98B8E49B17FB5249002F8DDB /* RVDrawingTutorialPage.xib in Resources */,\n\t\t\t\t98FDDB401801E4A600F16136 /* model1.rvlvd in Resources */,\n\t\t\t\t985E10EF17CA778C00BE4C28 /* RVDrawViewController.xib in Resources */,\n\t\t\t\t98ADF01D17FDF86200D58007 /* RVFinishTutorialPage.xib in Resources */,\n\t\t\t\t98FB7EC717AD864A000262F2 /* RVModelShader.vsh in Resources */,\n\t\t\t\t9832A666186DEB7A003501AE /* RVExportViewController.xib in Resources */,\n\t\t\t\t98FB7EC817AD864A000262F2 /* RVModelShader.fsh in Resources */,\n\t\t\t\t98D6BA0817F0EF2200BFEDB4 /* RVCreditsViewController.xib in Resources */,\n\t\t\t\t98FDDB421801E4A600F16136 /* model3.rvlvd in Resources */,\n\t\t\t\t98ADF00517FCB44900D58007 /* RVSelectTutorialPage.xib in Resources */,\n\t\t\t\t9872E2F117EB17E2000385EC /* mail.txt in Resources */,\n\t\t\t\t98B8E4C917FCB2C3002F8DDB /* RVStartTutorialPage.xib in Resources */,\n\t\t\t\t9873945F17C400BB0067FED5 /* RVModelsViewController.xib in Resources */,\n\t\t\t\t98FDDB37180176A000F16136 /* noise.png in Resources */,\n\t\t\t\t98C5FEAA17B2D93700022331 /* RVLineShader.vsh in Resources */,\n\t\t\t\t980CC35E17F0AECD0057D5AD /* RVSettingsButtonsView.xib in Resources */,\n\t\t\t\t98C5FEA917B2D93700022331 /* RVLineShader.fsh in Resources */,\n\t\t\t\t982D8D0217DCDEB6004C273F /* RVRootViewController.xib in Resources */,\n\t\t\t\t9872E30017EDF37D000385EC /* RVTutorialViewController.xib in Resources */,\n\t\t\t\t98B8E48E17FB3EDE002F8DDB /* RVSegmentsTutorialPage.xib in Resources */,\n\t\t\t\t9873946817C405130067FED5 /* RVPictureViewController.xib in Resources */,\n\t\t\t\t9873946117C400D30067FED5 /* Images.xcassets in Resources */,\n\t\t\t\t98FDDB411801E4A600F16136 /* model2.rvlvd in Resources */,\n\t\t\t\t9852519117BD326600B348F4 /* RVPointShader.vsh in Resources */,\n\t\t\t\t9852519217BD326600B348F4 /* RVPointShader.fsh in Resources */,\n\t\t\t\t98C5FE9C17B2BAFD00022331 /* RVModelViewController.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t98FB7E6417AD75D3000262F2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98557F6D17DCD26A0062472B /* RVRenderingController.m in Sources */,\n\t\t\t\t9861247E17C7FA290051C092 /* RVModelManager.m in Sources */,\n\t\t\t\t9873947317C559790067FED5 /* RVOpenGLView.m in Sources */,\n\t\t\t\t98475ACE17C0D232002FD2AB /* RVColorProvider.m in Sources */,\n\t\t\t\t98EAA2301804AC6800D0B527 /* RVTutorialScrollView.m in Sources */,\n\t\t\t\t9873945E17C400BB0067FED5 /* RVModelsViewController.m in Sources */,\n\t\t\t\t98A3452417B7AD2900D0C82F /* RVGuideline.m in Sources */,\n\t\t\t\t98A3452117B7A16300D0C82F /* RVSegmentConnection.m in Sources */,\n\t\t\t\t9872E2FB17EDF2BB000385EC /* RVTutorialPage.m in Sources */,\n\t\t\t\t9852518817BD1F9C00B348F4 /* RVEndPoint.m in Sources */,\n\t\t\t\t981395A917DD144700C17CB1 /* RVQuaternionAnimation.m in Sources */,\n\t\t\t\t98A3451C17B6CAE700D0C82F /* RVMeshController.m in Sources */,\n\t\t\t\t9832A67A186E0F98003501AE /* mztools.c in Sources */,\n\t\t\t\t98D6BA0717F0EF2200BFEDB4 /* RVCreditsViewController.m in Sources */,\n\t\t\t\t98FB7E7817AD75D3000262F2 /* main.m in Sources */,\n\t\t\t\t98557F6717D7C6190062472B /* RVGuidelineDotSprite.m in Sources */,\n\t\t\t\t98FB7E7C17AD75D3000262F2 /* AppDelegate.m in Sources */,\n\t\t\t\t98ED503017C7CCDA00E5FE1F /* RVModelSerializer.m in Sources */,\n\t\t\t\t98557F6417D6758D0062472B /* RVAxisSprite.m in Sources */,\n\t\t\t\t9850E0AC17F74376006B8ACD /* UIView+RotationAnimation.m in Sources */,\n\t\t\t\t98294FAC17CFD852003CAE5F /* NSArray+Functional.m in Sources */,\n\t\t\t\t98B8E49917FB5233002F8DDB /* RVDrawingTutorialPage.m in Sources */,\n\t\t\t\t98C5FE9417B2B56800022331 /* RVDrawViewController.m in Sources */,\n\t\t\t\t9861248E17C802060051C092 /* UIColor+RevolvedColors.m in Sources */,\n\t\t\t\t98A9800517E8FCD500F09CFD /* RVModelButtonsView.m in Sources */,\n\t\t\t\t98A3451917B6CAD500D0C82F /* RVPointMeshController.m in Sources */,\n\t\t\t\t9852518217BD1F8400B348F4 /* RVAnchorPoint.m in Sources */,\n\t\t\t\t98B8E4C717FCB2BD002F8DDB /* RVStartTutorialPage.m in Sources */,\n\t\t\t\t9852518E17BD324900B348F4 /* RVPointShader.m in Sources */,\n\t\t\t\t985E10E817CA6B1600BE4C28 /* RVFloatAnimation.m in Sources */,\n\t\t\t\t9861248317C7FCC80051C092 /* RVModel.m in Sources */,\n\t\t\t\t98ADF01B17FDF85C00D58007 /* RVFinishTutorialPage.m in Sources */,\n\t\t\t\t98FB7E9117AD76BF000262F2 /* RVSegment.m in Sources */,\n\t\t\t\t9832A67C186E0F98003501AE /* zip.c in Sources */,\n\t\t\t\t98FB7E9D17AD78F0000262F2 /* RVModelViewController.m in Sources */,\n\t\t\t\t98C5FEA217B2CA0300022331 /* RVLineMeshController.m in Sources */,\n\t\t\t\t988180C617F2361200C0E6BD /* MFMailComposeViewController+SendIfPossible.m in Sources */,\n\t\t\t\t9873945717C200B40067FED5 /* RVLineSprite.m in Sources */,\n\t\t\t\t98FDDB3C1801930F00F16136 /* RVColorPickerButton.m in Sources */,\n\t\t\t\t98C5FEAD17B2EFCD00022331 /* DrawGestureRecognizer.m in Sources */,\n\t\t\t\t9861249417C8DDBB0051C092 /* RVRootViewController.m in Sources */,\n\t\t\t\t9861248717C8012D0051C092 /* RVModelCell.m in Sources */,\n\t\t\t\t9852519517BEC58200B348F4 /* RVDeleteView.m in Sources */,\n\t\t\t\t98FB7EAE17AD7F21000262F2 /* CameraController.m in Sources */,\n\t\t\t\t98B8E4A817FB5FA1002F8DDB /* RVRevolvedTutorialPage.m in Sources */,\n\t\t\t\t98B8E48C17FB3ECD002F8DDB /* RVSegmentsTutorialPage.m in Sources */,\n\t\t\t\t9859CA1317E625AC000E539F /* NSMutableArray+MoveObject.m in Sources */,\n\t\t\t\t985E10DC17CA54F300BE4C28 /* NSMapTable+BlockEnumeration.m in Sources */,\n\t\t\t\t98557F6A17D7CB300062472B /* RVGuidlineDotMeshController.m in Sources */,\n\t\t\t\t985E10E117CA688400BE4C28 /* RVAnimator.m in Sources */,\n\t\t\t\t9859CA1617E627BA000E539F /* NSMutableOrderedSet+MoveObject.m in Sources */,\n\t\t\t\t9832A679186E0F98003501AE /* ioapi.c in Sources */,\n\t\t\t\t985E10E517CA691100BE4C28 /* RVAnimation.m in Sources */,\n\t\t\t\t98B8E4AD17FB695F002F8DDB /* RVTutorialLineImageView.m in Sources */,\n\t\t\t\t98294FB317D361C6003CAE5F /* RVModelMetadata.m in Sources */,\n\t\t\t\t9873945A17C200FC0067FED5 /* RVPointSprite.m in Sources */,\n\t\t\t\t9832A665186DEB7A003501AE /* RVExportViewController.m in Sources */,\n\t\t\t\t98FB7EB117AD7FD4000262F2 /* Camera.m in Sources */,\n\t\t\t\t98294FB017D354A1003CAE5F /* NSError+RevolvedErrors.m in Sources */,\n\t\t\t\t9852517D17BC09C600B348F4 /* RVColorPicker.m in Sources */,\n\t\t\t\t98CD44DA18303F0D004D1986 /* RVExporter.m in Sources */,\n\t\t\t\t9832A67B186E0F98003501AE /* unzip.c in Sources */,\n\t\t\t\t98CD44DD18304056004D1986 /* RVSTLExporter.m in Sources */,\n\t\t\t\t9873945317C200910067FED5 /* RVSprite.m in Sources */,\n\t\t\t\t98B8E4C217FC87BE002F8DDB /* RVBendTutorialPage.m in Sources */,\n\t\t\t\t985E10EB17CA6B2200BE4C28 /* RVVectorAnimation.m in Sources */,\n\t\t\t\t98C5FEA617B2D8AC00022331 /* RVLineShader.m in Sources */,\n\t\t\t\t9872E2FF17EDF37D000385EC /* RVTutorialViewController.m in Sources */,\n\t\t\t\t98FB7EBA17AD8480000262F2 /* RVModelMeshController.m in Sources */,\n\t\t\t\t9872E2F417EBA5A9000385EC /* RVUserDefaults.m in Sources */,\n\t\t\t\t98FB7EBB17AD8480000262F2 /* Renderer.m in Sources */,\n\t\t\t\t98A9800B17E8FD9500F09CFD /* RVPreviewViewController.m in Sources */,\n\t\t\t\t9832A66C186E0E72003501AE /* SSZipArchive.m in Sources */,\n\t\t\t\t9852518517BD1F9300B348F4 /* RVControlPoint.m in Sources */,\n\t\t\t\t98FB7EC517AD864A000262F2 /* BCShader.m in Sources */,\n\t\t\t\t98ADF00317FCB44200D58007 /* RVSelectTutorialPage.m in Sources */,\n\t\t\t\t98C5FEB317B65EE400022331 /* RVDrawController.m in Sources */,\n\t\t\t\t980CC35C17F0AEAE0057D5AD /* RVSettingsButtonsView.m in Sources */,\n\t\t\t\t98FB7EC617AD864A000262F2 /* RVModelShader.m in Sources */,\n\t\t\t\t9859CA1E17E651B4000E539F /* RVAddProgressView.m in Sources */,\n\t\t\t\t98ADF01017FCBE7000D58007 /* RVPassForwardView.m in Sources */,\n\t\t\t\t98C5FEB917B66BEB00022331 /* RVPoint.m in Sources */,\n\t\t\t\t98C5FE9F17B2BC9D00022331 /* RVSpaceConverter.m in Sources */,\n\t\t\t\t98557F5E17D53E7D0062472B /* RVAxisMeshController.m in Sources */,\n\t\t\t\t986C0C3F183816F300F8F51D /* RVOBJExporter.m in Sources */,\n\t\t\t\t98294FBB17D53157003CAE5F /* RVAxisShader.m in Sources */,\n\t\t\t\t985E10D917C946E600BE4C28 /* RVModelSprite.m in Sources */,\n\t\t\t\t9873946717C405130067FED5 /* RVPictureViewController.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t98ED508117C7CF6800E5FE1F /* InfoPlist.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98ED508217C7CF6800E5FE1F /* en */,\n\t\t\t);\n\t\t\tname = InfoPlist.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98FB7E7417AD75D3000262F2 /* InfoPlist.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98FB7E7517AD75D3000262F2 /* en */,\n\t\t\t);\n\t\t\tname = InfoPlist.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t98FB7E8917AD75D3000262F2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 2;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t98FB7E8A17AD75D3000262F2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tOTHER_CFLAGS = \"-DNS_BLOCK_ASSERTIONS=1\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 2;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t98FB7E8C17AD75D3000262F2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tARCHS = \"$(ARCHS_STANDARD_INCLUDING_64_BIT)\";\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tGCC_FAST_MATH = YES;\n\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;\n\t\t\t\tGCC_PREFIX_HEADER = \"Revolved/Revolved-Prefix.pch\";\n\t\t\t\tINFOPLIST_FILE = \"Revolved/Revolved-Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tPRODUCT_NAME = Revolved;\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 2;\n\t\t\t\tWRAPPER_EXTENSION = app;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t98FB7E8D17AD75D3000262F2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tARCHS = \"$(ARCHS_STANDARD_INCLUDING_64_BIT)\";\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tGCC_FAST_MATH = YES;\n\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;\n\t\t\t\tGCC_PREFIX_HEADER = \"Revolved/Revolved-Prefix.pch\";\n\t\t\t\tINFOPLIST_FILE = \"Revolved/Revolved-Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tPRODUCT_NAME = Revolved;\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 2;\n\t\t\t\tWRAPPER_EXTENSION = app;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t98FDDB461801FB6B00F16136 /* AdHoc */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer: Bartosz Ciechanowski (69S9R99KL3)\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tOTHER_CFLAGS = \"-DNS_BLOCK_ASSERTIONS=1\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 2;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = AdHoc;\n\t\t};\n\t\t98FDDB471801FB6B00F16136 /* AdHoc */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tARCHS = \"$(ARCHS_STANDARD_INCLUDING_64_BIT)\";\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tGCC_FAST_MATH = YES;\n\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;\n\t\t\t\tGCC_PREFIX_HEADER = \"Revolved/Revolved-Prefix.pch\";\n\t\t\t\tINFOPLIST_FILE = \"Revolved/Revolved-Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tPRODUCT_NAME = Revolved;\n\t\t\t\tPROVISIONING_PROFILE = \"BFF902A3-388D-46AC-909A-1DF3A908F17E\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 2;\n\t\t\t\tWRAPPER_EXTENSION = app;\n\t\t\t};\n\t\t\tname = AdHoc;\n\t\t};\n\t\t98FDDB491801FB7000F16136 /* Distribution */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer: Bartosz Ciechanowski (69S9R99KL3)\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tOTHER_CFLAGS = \"-DNS_BLOCK_ASSERTIONS=1\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 2;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Distribution;\n\t\t};\n\t\t98FDDB4A1801FB7000F16136 /* Distribution */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tARCHS = \"$(ARCHS_STANDARD_INCLUDING_64_BIT)\";\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tGCC_FAST_MATH = YES;\n\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;\n\t\t\t\tGCC_PREFIX_HEADER = \"Revolved/Revolved-Prefix.pch\";\n\t\t\t\tINFOPLIST_FILE = \"Revolved/Revolved-Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 7.0;\n\t\t\t\tPRODUCT_NAME = Revolved;\n\t\t\t\tPROVISIONING_PROFILE = \"AEBFC96F-58A6-40E3-A075-6D947DCF0841\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 2;\n\t\t\t\tWRAPPER_EXTENSION = app;\n\t\t\t};\n\t\t\tname = Distribution;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t98FB7E6317AD75D3000262F2 /* Build configuration list for PBXProject \"Revolved\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t98FB7E8917AD75D3000262F2 /* Debug */,\n\t\t\t\t98FB7E8A17AD75D3000262F2 /* Release */,\n\t\t\t\t98FDDB461801FB6B00F16136 /* AdHoc */,\n\t\t\t\t98FDDB491801FB7000F16136 /* Distribution */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t98FB7E8B17AD75D3000262F2 /* Build configuration list for PBXNativeTarget \"Revolved\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t98FB7E8C17AD75D3000262F2 /* Debug */,\n\t\t\t\t98FB7E8D17AD75D3000262F2 /* Release */,\n\t\t\t\t98FDDB471801FB6B00F16136 /* AdHoc */,\n\t\t\t\t98FDDB4A1801FB7000F16136 /* Distribution */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 98FB7E6017AD75D3000262F2 /* Project object */;\n}\n"
  },
  {
    "path": "Revolved.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:Revolved.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  }
]