You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2016/02/16 14:15:59 UTC

[67/75] usergrid git commit: Major Updates. See commit details.

http://git-wip-us.apache.org/repos/asf/usergrid/blob/c638c774/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextViewController.m
----------------------------------------------------------------------
diff --git a/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextViewController.m b/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextViewController.m
deleted file mode 100644
index 5febfcb..0000000
--- a/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextViewController.m
+++ /dev/null
@@ -1,2392 +0,0 @@
-//
-//   Copyright 2014 Slack Technologies, Inc.
-//
-//   Licensed under the Apache License, Version 2.0 (the "License");
-//   you may not use this file except in compliance with the License.
-//   You may obtain a copy of the License at
-//
-//       http://www.apache.org/licenses/LICENSE-2.0
-//
-//   Unless required by applicable law or agreed to in writing, software
-//   distributed under the License is distributed on an "AS IS" BASIS,
-//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//   See the License for the specific language governing permissions and
-//   limitations under the License.
-//
-
-#import "SLKTextViewController.h"
-#import "SLKInputAccessoryView.h"
-
-#import "UIResponder+SLKAdditions.h"
-
-/** Feature flagged while waiting to implement a more reliable technique. */
-#define SLKBottomPanningEnabled 0
-
-#define kSLKAlertViewClearTextTag [NSStringFromClass([SLKTextViewController class]) hash]
-
-NSString * const SLKKeyboardWillShowNotification =      @"SLKKeyboardWillShowNotification";
-NSString * const SLKKeyboardDidShowNotification =       @"SLKKeyboardDidShowNotification";
-NSString * const SLKKeyboardWillHideNotification =      @"SLKKeyboardWillHideNotification";
-NSString * const SLKKeyboardDidHideNotification =       @"SLKKeyboardDidHideNotification";
-
-CGFloat const SLKAutoCompletionViewDefaultHeight = 140.0;
-
-@interface SLKTextViewController ()
-{
-    CGPoint _scrollViewOffsetBeforeDragging;
-    CGFloat _keyboardHeightBeforeDragging;
-}
-
-// The shared scrollView pointer, either a tableView or collectionView
-@property (nonatomic, weak) UIScrollView *scrollViewProxy;
-
-// A hairline displayed on top of the auto-completion view, to better separate the content from the control.
-@property (nonatomic, strong) UIView *autoCompletionHairline;
-
-// Auto-Layout height constraints used for updating their constants
-@property (nonatomic, strong) NSLayoutConstraint *scrollViewHC;
-@property (nonatomic, strong) NSLayoutConstraint *textInputbarHC;
-@property (nonatomic, strong) NSLayoutConstraint *typingIndicatorViewHC;
-@property (nonatomic, strong) NSLayoutConstraint *autoCompletionViewHC;
-@property (nonatomic, strong) NSLayoutConstraint *keyboardHC;
-
-// YES if the user is moving the keyboard with a gesture
-@property (nonatomic, assign, getter = isMovingKeyboard) BOOL movingKeyboard;
-
-// The current keyboard status (hidden, showing, etc.)
-@property (nonatomic) SLKKeyboardStatus keyboardStatus;
-
-// YES if the view controller did appear and everything is finished configurating. This allows blocking some layout animations among other things.
-@property (nonatomic, getter=isViewVisible) BOOL viewVisible;
-
-// YES if the view controller's view's size is changing by its parent (i.e. when its window rotates or is resized)
-@property (nonatomic, getter = isTransitioning) BOOL transitioning;
-
-// Optional classes to be used instead of the default ones.
-@property (nonatomic, strong) Class textViewClass;
-@property (nonatomic, strong) Class typingIndicatorViewClass;
-
-@end
-
-@implementation SLKTextViewController
-@synthesize tableView = _tableView;
-@synthesize collectionView = _collectionView;
-@synthesize scrollView = _scrollView;
-@synthesize typingIndicatorProxyView = _typingIndicatorProxyView;
-@synthesize textInputbar = _textInputbar;
-@synthesize autoCompletionView = _autoCompletionView;
-@synthesize autoCompleting = _autoCompleting;
-@synthesize scrollViewProxy = _scrollViewProxy;
-@synthesize presentedInPopover = _presentedInPopover;
-
-#pragma mark - Initializer
-
-- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
-{
-    return [self initWithTableViewStyle:UITableViewStylePlain];
-}
-
-- (instancetype)init
-{
-    return [self initWithTableViewStyle:UITableViewStylePlain];
-}
-
-- (instancetype)initWithTableViewStyle:(UITableViewStyle)style
-{
-    NSAssert([self class] != [SLKTextViewController class], @"Oops! You must subclass SLKTextViewController.");
-    
-    if (self = [super initWithNibName:nil bundle:nil])
-    {
-        self.scrollViewProxy = [self tableViewWithStyle:style];
-        [self slk_commonInit];
-    }
-    return self;
-}
-
-- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
-{
-    NSAssert([self class] != [SLKTextViewController class], @"Oops! You must subclass SLKTextViewController.");
-    
-    if (self = [super initWithNibName:nil bundle:nil])
-    {
-        self.scrollViewProxy = [self collectionViewWithLayout:layout];
-        [self slk_commonInit];
-    }
-    return self;
-}
-
-- (instancetype)initWithScrollView:(UIScrollView *)scrollView
-{
-    NSAssert([self class] != [SLKTextViewController class], @"Oops! You must subclass SLKTextViewController.");
-    
-    if (self = [super initWithNibName:nil bundle:nil])
-    {
-        _scrollView = scrollView;
-        _scrollView.translatesAutoresizingMaskIntoConstraints = NO; // Makes sure the scrollView plays nice with auto-layout
-        
-        self.scrollViewProxy = _scrollView;
-        [self slk_commonInit];
-    }
-    return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)decoder
-{
-    NSAssert([self class] != [SLKTextViewController class], @"Oops! You must subclass SLKTextViewController.");
-    
-    if (self = [super initWithCoder:decoder])
-    {
-        UITableViewStyle tableViewStyle = [[self class] tableViewStyleForCoder:decoder];
-        UICollectionViewLayout *collectionViewLayout = [[self class] collectionViewLayoutForCoder:decoder];
-        
-        if ([collectionViewLayout isKindOfClass:[UICollectionViewLayout class]]) {
-            self.scrollViewProxy = [self collectionViewWithLayout:collectionViewLayout];
-        }
-        else {
-            self.scrollViewProxy = [self tableViewWithStyle:tableViewStyle];
-        }
-        
-        [self slk_commonInit];
-    }
-    return self;
-}
-
-- (void)slk_commonInit
-{
-    [self slk_registerNotifications];
-    
-    self.bounces = YES;
-    self.inverted = YES;
-    self.shakeToClearEnabled = NO;
-    self.keyboardPanningEnabled = YES;
-    self.shouldClearTextAtRightButtonPress = YES;
-    self.shouldScrollToBottomAfterKeyboardShows = NO;
-    
-    self.automaticallyAdjustsScrollViewInsets = YES;
-    self.extendedLayoutIncludesOpaqueBars = YES;
-}
-
-
-#pragma mark - View lifecycle
-
-- (void)loadView
-{
-    [super loadView];
-}
-
-- (void)viewDidLoad
-{
-    [super viewDidLoad];
-    
-    [self.view addSubview:self.scrollViewProxy];
-    [self.view addSubview:self.autoCompletionView];
-    [self.view addSubview:self.typingIndicatorProxyView];
-    [self.view addSubview:self.textInputbar];
-    
-    [self slk_setupViewConstraints];
-}
-
-- (void)viewWillAppear:(BOOL)animated
-{
-    [super viewWillAppear:animated];
-    
-    // Invalidates this flag when the view appears
-    self.textView.didNotResignFirstResponder = NO;
-    
-    // Forces laying out the recently added subviews and update their constraints
-    [self.view layoutIfNeeded];
-    
-    [UIView performWithoutAnimation:^{
-        // Reloads any cached text
-        [self slk_reloadTextView];
-    }];
-}
-
-- (void)viewDidAppear:(BOOL)animated
-{
-    [super viewDidAppear:animated];
-    
-    [self.scrollViewProxy flashScrollIndicators];
-    
-    self.viewVisible = YES;
-}
-
-- (void)viewWillDisappear:(BOOL)animated
-{
-    [super viewWillDisappear:animated];
-    
-    // Stops the keyboard from being dismissed during the navigation controller's "swipe-to-pop"
-    self.textView.didNotResignFirstResponder = self.isMovingFromParentViewController;
-    
-    self.viewVisible = NO;
-    
-    // Caches the text before it's too late!
-    [self slk_cacheTextView];
-}
-
-- (void)viewDidDisappear:(BOOL)animated
-{
-    [super viewDidDisappear:animated];
-}
-
-- (void)viewWillLayoutSubviews
-{
-    [super viewWillLayoutSubviews];
-    
-    [self slk_adjustContentConfigurationIfNeeded];
-}
-
-- (void)viewDidLayoutSubviews
-{
-    [super viewDidLayoutSubviews];
-}
-
-
-#pragma mark - Getters
-
-+ (UITableViewStyle)tableViewStyleForCoder:(NSCoder *)decoder
-{
-    return UITableViewStylePlain;
-}
-
-+ (UICollectionViewLayout *)collectionViewLayoutForCoder:(NSCoder *)decoder
-{
-    return nil;
-}
-
-- (UITableView *)tableViewWithStyle:(UITableViewStyle)style
-{
-    if (!_tableView) {
-        _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:style];
-        _tableView.translatesAutoresizingMaskIntoConstraints = NO;
-        _tableView.scrollsToTop = YES;
-        _tableView.dataSource = self;
-        _tableView.delegate = self;
-        _tableView.clipsToBounds = NO;
-    }
-    return _tableView;
-}
-
-- (UICollectionView *)collectionViewWithLayout:(UICollectionViewLayout *)layout
-{
-    if (!_collectionView) {
-        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
-        _collectionView.translatesAutoresizingMaskIntoConstraints = NO;
-        _collectionView.scrollsToTop = YES;
-        _collectionView.dataSource = self;
-        _collectionView.delegate = self;
-    }
-    return _collectionView;
-}
-
-- (UITableView *)autoCompletionView
-{
-    if (!_autoCompletionView) {
-        _autoCompletionView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
-        _autoCompletionView.translatesAutoresizingMaskIntoConstraints = NO;
-        _autoCompletionView.backgroundColor = [UIColor colorWithWhite:0.97 alpha:1.0];
-        _autoCompletionView.scrollsToTop = NO;
-        _autoCompletionView.dataSource = self;
-        _autoCompletionView.delegate = self;
-        
-#ifdef __IPHONE_9_0
-        if ([_autoCompletionView respondsToSelector:@selector(cellLayoutMarginsFollowReadableWidth)]) {
-            _autoCompletionView.cellLayoutMarginsFollowReadableWidth = NO;
-        }
-#endif
-        
-        CGRect rect = CGRectZero;
-        rect.size = CGSizeMake(CGRectGetWidth(self.view.frame), 0.5);
-        
-        _autoCompletionHairline = [[UIView alloc] initWithFrame:rect];
-        _autoCompletionHairline.autoresizingMask = UIViewAutoresizingFlexibleWidth;
-        _autoCompletionHairline.backgroundColor = _autoCompletionView.separatorColor;
-        [_autoCompletionView addSubview:_autoCompletionHairline];
-    }
-    return _autoCompletionView;
-}
-
-- (SLKTextInputbar *)textInputbar
-{
-    if (!_textInputbar) {
-        _textInputbar = [[SLKTextInputbar alloc] initWithTextViewClass:self.textViewClass];
-        _textInputbar.translatesAutoresizingMaskIntoConstraints = NO;
-        _textInputbar.controller = self;
-        
-        [_textInputbar.leftButton addTarget:self action:@selector(didPressLeftButton:) forControlEvents:UIControlEventTouchUpInside];
-        [_textInputbar.rightButton addTarget:self action:@selector(didPressRightButton:) forControlEvents:UIControlEventTouchUpInside];
-        [_textInputbar.editorLeftButton addTarget:self action:@selector(didCancelTextEditing:) forControlEvents:UIControlEventTouchUpInside];
-        [_textInputbar.editorRightButton addTarget:self action:@selector(didCommitTextEditing:) forControlEvents:UIControlEventTouchUpInside];
-        
-        _textInputbar.textView.delegate = self;
-        
-        _verticalPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(slk_didPanTextInputBar:)];
-        _verticalPanGesture.delegate = self;
-        
-        [_textInputbar addGestureRecognizer:self.verticalPanGesture];
-    }
-    return _textInputbar;
-}
-
-- (UIView <SLKTypingIndicatorProtocol> *)typingIndicatorProxyView
-{
-    if (!_typingIndicatorProxyView) {
-        Class class = self.typingIndicatorViewClass ? : [SLKTypingIndicatorView class];
-        
-        _typingIndicatorProxyView = [[class alloc] init];
-        _typingIndicatorProxyView.translatesAutoresizingMaskIntoConstraints = NO;
-        _typingIndicatorProxyView.hidden = YES;
-        
-        [_typingIndicatorProxyView addObserver:self forKeyPath:@"visible" options:NSKeyValueObservingOptionNew context:nil];
-    }
-    return _typingIndicatorProxyView;
-}
-
-- (SLKTypingIndicatorView *)typingIndicatorView
-{
-    if ([_typingIndicatorProxyView isKindOfClass:[SLKTypingIndicatorView class]]) {
-        return (SLKTypingIndicatorView *)self.typingIndicatorProxyView;
-    }
-    return nil;
-}
-
-- (BOOL)isPresentedInPopover
-{
-    return _presentedInPopover && SLK_IS_IPAD;
-}
-
-- (SLKTextView *)textView
-{
-    return self.textInputbar.textView;
-}
-
-- (UIButton *)leftButton
-{
-    return self.textInputbar.leftButton;
-}
-
-- (UIButton *)rightButton
-{
-    return self.textInputbar.rightButton;
-}
-
-- (UIModalPresentationStyle)modalPresentationStyle
-{
-    if (self.navigationController) {
-        return self.navigationController.modalPresentationStyle;
-    }
-    return [super modalPresentationStyle];
-}
-
-- (CGFloat)slk_appropriateKeyboardHeightFromNotification:(NSNotification *)notification
-{
-    // Let's first detect keyboard special states such as external keyboard, undocked or split layouts.
-    [self slk_detectKeyboardStatesInNotification:notification];
-    
-    if ([self ignoreTextInputbarAdjustment]) {
-        return [self slk_appropriateBottomMargin];
-    }
-    
-    CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
-    
-    return [self slk_appropriateKeyboardHeightFromRect:keyboardRect];
-}
-
-- (CGFloat)slk_appropriateKeyboardHeightFromRect:(CGRect)rect
-{
-    CGRect keyboardRect = [self.view convertRect:rect fromView:nil];
-    
-    CGFloat viewHeight = CGRectGetHeight(self.view.bounds);
-    CGFloat keyboardMinY = CGRectGetMinY(keyboardRect);
-    
-    CGFloat keyboardHeight = MAX(0.0, viewHeight - keyboardMinY);
-    CGFloat bottomMargin = [self slk_appropriateBottomMargin];
-    
-    // When the keyboard height is zero, we can assume there is no keyboard visible
-    // In that case, let's see if there are any other views outside of the view hiearchy
-    // requiring to adjust the text input bottom margin
-    if (keyboardHeight < bottomMargin) {
-        keyboardHeight = bottomMargin;
-    }
-    
-    return keyboardHeight;
-}
-
-- (CGFloat)slk_appropriateBottomMargin
-{
-    // A bottom margin is required only if the view is extended out of it bounds
-    if ((self.edgesForExtendedLayout & UIRectEdgeBottom) > 0) {
-        if (self.tabBarController) {
-            return CGRectGetHeight(self.tabBarController.tabBar.frame);
-        }
-    }
-    
-    return 0.0;
-}
-
-- (CGFloat)slk_appropriateScrollViewHeight
-{
-    CGFloat scrollViewHeight = CGRectGetHeight(self.view.bounds);
-    
-    scrollViewHeight -= self.keyboardHC.constant;
-    scrollViewHeight -= self.textInputbarHC.constant;
-    scrollViewHeight -= self.autoCompletionViewHC.constant;
-    scrollViewHeight -= self.typingIndicatorViewHC.constant;
-    
-    if (scrollViewHeight < 0) return 0;
-    else return scrollViewHeight;
-}
-
-- (CGFloat)slk_topBarsHeight
-{
-    // No need to adjust if the edge isn't available
-    if ((self.edgesForExtendedLayout & UIRectEdgeTop) == 0) {
-        return 0.0;
-    }
-    
-    CGFloat topBarsHeight = CGRectGetHeight(self.navigationController.navigationBar.frame);
-    
-    if ((SLK_IS_IPHONE && SLK_IS_LANDSCAPE && SLK_IS_IOS8_AND_HIGHER) ||
-        (SLK_IS_IPAD && self.modalPresentationStyle == UIModalPresentationFormSheet) ||
-        self.isPresentedInPopover) {
-        return topBarsHeight;
-    }
-    
-    topBarsHeight += CGRectGetHeight([UIApplication sharedApplication].statusBarFrame);
-    
-    return topBarsHeight;
-}
-
-- (NSString *)slk_appropriateKeyboardNotificationName:(NSNotification *)notification
-{
-    NSString *name = notification.name;
-    
-    if ([name isEqualToString:UIKeyboardWillShowNotification]) {
-        return SLKKeyboardWillShowNotification;
-    }
-    if ([name isEqualToString:UIKeyboardWillHideNotification]) {
-        return SLKKeyboardWillHideNotification;
-    }
-    if ([name isEqualToString:UIKeyboardDidShowNotification]) {
-        return SLKKeyboardDidShowNotification;
-    }
-    if ([name isEqualToString:UIKeyboardDidHideNotification]) {
-        return SLKKeyboardDidHideNotification;
-    }
-    return nil;
-}
-
-- (SLKKeyboardStatus)slk_keyboardStatusForNotification:(NSNotification *)notification
-{
-    NSString *name = notification.name;
-    
-    if ([name isEqualToString:UIKeyboardWillShowNotification]) {
-        return SLKKeyboardStatusWillShow;
-    }
-    if ([name isEqualToString:UIKeyboardDidShowNotification]) {
-        return SLKKeyboardStatusDidShow;
-    }
-    if ([name isEqualToString:UIKeyboardWillHideNotification]) {
-        return SLKKeyboardStatusWillHide;
-    }
-    if ([name isEqualToString:UIKeyboardDidHideNotification]) {
-        return SLKKeyboardStatusDidHide;
-    }
-    return -1;
-}
-
-- (BOOL)slk_isIllogicalKeyboardStatus:(SLKKeyboardStatus)newStatus
-{
-    if ((self.keyboardStatus == SLKKeyboardStatusDidHide && newStatus == SLKKeyboardStatusWillShow) ||
-        (self.keyboardStatus == SLKKeyboardStatusWillShow && newStatus == SLKKeyboardStatusDidShow) ||
-        (self.keyboardStatus == SLKKeyboardStatusDidShow && newStatus == SLKKeyboardStatusWillHide) ||
-        (self.keyboardStatus == SLKKeyboardStatusWillHide && newStatus == SLKKeyboardStatusDidHide)) {
-        return NO;
-    }
-    return YES;
-}
-
-
-#pragma mark - Setters
-
-- (void)setEdgesForExtendedLayout:(UIRectEdge)rectEdge
-{
-    if (self.edgesForExtendedLayout == rectEdge) {
-        return;
-    }
-    
-    [super setEdgesForExtendedLayout:rectEdge];
-    
-    [self slk_updateViewConstraints];
-}
-
-- (void)setScrollViewProxy:(UIScrollView *)scrollView
-{
-    if ([_scrollViewProxy isEqual:scrollView]) {
-        return;
-    }
-    
-    _singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(slk_didTapScrollView:)];
-    _singleTapGesture.delegate = self;
-    [_singleTapGesture requireGestureRecognizerToFail:scrollView.panGestureRecognizer];
-    
-    [scrollView addGestureRecognizer:self.singleTapGesture];
-    
-    [scrollView.panGestureRecognizer addTarget:self action:@selector(slk_didPanTextInputBar:)];
-    
-    _scrollViewProxy = scrollView;
-}
-
-- (void)setAutoCompleting:(BOOL)autoCompleting
-{
-    if (_autoCompleting == autoCompleting) {
-        return;
-    }
-    
-    _autoCompleting = autoCompleting;
-    
-    self.scrollViewProxy.scrollEnabled = !autoCompleting;
-}
-
-- (void)setInverted:(BOOL)inverted
-{
-    if (_inverted == inverted) {
-        return;
-    }
-    
-    _inverted = inverted;
-    
-    self.scrollViewProxy.transform = inverted ? CGAffineTransformMake(1, 0, 0, -1, 0, 0) : CGAffineTransformIdentity;
-}
-
-- (BOOL)slk_updateKeyboardStatus:(SLKKeyboardStatus)status
-{
-    // Skips if trying to update the same status
-    if (_keyboardStatus == status) {
-        return NO;
-    }
-    
-    // Skips illogical conditions
-    if ([self slk_isIllogicalKeyboardStatus:status]) {
-        return NO;
-    }
-    
-    _keyboardStatus = status;
-    
-    [self didChangeKeyboardStatus:status];
-    
-    return YES;
-}
-
-
-#pragma mark - Public & Subclassable Methods
-
-- (void)presentKeyboard:(BOOL)animated
-{
-    // Skips if already first responder
-    if ([self.textView isFirstResponder]) {
-        return;
-    }
-    
-    if (!animated) {
-        [UIView performWithoutAnimation:^{
-            [self.textView becomeFirstResponder];
-        }];
-    }
-    else {
-        [self.textView becomeFirstResponder];
-    }
-}
-
-- (void)dismissKeyboard:(BOOL)animated
-{
-    // Dismisses the keyboard from any first responder in the window.
-    if (![self.textView isFirstResponder] && self.keyboardHC.constant > 0) {
-        [self.view.window endEditing:NO];
-    }
-    
-    if (!animated) {
-        [UIView performWithoutAnimation:^{
-            [self.textView resignFirstResponder];
-        }];
-    }
-    else {
-        [self.textView resignFirstResponder];
-    }
-}
-
-- (BOOL)forceTextInputbarAdjustmentForResponder:(UIResponder *)responder
-{
-    return NO;
-}
-
-- (BOOL)ignoreTextInputbarAdjustment
-{
-    if (self.isExternalKeyboardDetected || self.isKeyboardUndocked) {
-        return YES;
-    }
-    
-    return NO;
-}
-
-- (void)didChangeKeyboardStatus:(SLKKeyboardStatus)status
-{
-    // No implementation here. Meant to be overriden in subclass.
-}
-
-- (void)textWillUpdate
-{
-    // No implementation here. Meant to be overriden in subclass.
-}
-
-- (void)textDidUpdate:(BOOL)animated
-{
-    if (self.textInputbarHidden) {
-        return;
-    }
-    
-    CGFloat inputbarHeight = self.textInputbar.appropriateHeight;
-    
-    self.textInputbar.rightButton.enabled = [self canPressRightButton];
-    self.textInputbar.editorRightButton.enabled = [self canPressRightButton];
-    
-    if (inputbarHeight != self.textInputbarHC.constant)
-    {
-        self.textInputbarHC.constant = inputbarHeight;
-        self.scrollViewHC.constant = [self slk_appropriateScrollViewHeight];
-        
-        if (animated) {
-            
-            BOOL bounces = self.bounces && [self.textView isFirstResponder];
-            
-            [self.view slk_animateLayoutIfNeededWithBounce:bounces
-                                                   options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionLayoutSubviews|UIViewAnimationOptionBeginFromCurrentState
-                                                animations:^{
-                                                    if (self.textInputbar.isEditing) {
-                                                        [self.textView slk_scrollToCaretPositonAnimated:NO];
-                                                    }
-                                                }];
-        }
-        else {
-            [self.view layoutIfNeeded];
-        }
-    }
-    
-    // Toggles auto-correction if requiered
-    [self slk_enableTypingSuggestionIfNeeded];
-}
-
-- (void)textSelectionDidChange
-{
-    // The text view must be first responder
-    if (![self.textView isFirstResponder]) {
-        return;
-    }
-    
-    // Skips there is a real text selection
-    if (self.textView.isTrackpadEnabled) {
-        return;
-    }
-    
-    if (self.textView.selectedRange.length > 0) {
-        if (self.isAutoCompleting) {
-            [self cancelAutoCompletion];
-        }
-        return;
-    }
-    
-    // Process the text at every caret movement
-    [self slk_processTextForAutoCompletion];
-}
-
-- (BOOL)canPressRightButton
-{
-    NSString *text = [self.textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
-    
-    if (text.length > 0 && ![self.textInputbar limitExceeded]) {
-        return YES;
-    }
-    
-    return NO;
-}
-
-- (void)didPressLeftButton:(id)sender
-{
-    // No implementation here. Meant to be overriden in subclass.
-}
-
-- (void)didPressRightButton:(id)sender
-{
-    if (self.shouldClearTextAtRightButtonPress) {
-        // Clears the text and the undo manager
-        [self.textView slk_clearText:YES];
-    }
-    
-    // Clears cache
-    [self clearCachedText];
-}
-
-- (void)editText:(NSString *)text
-{
-    if (![self.textInputbar canEditText:text]) {
-        return;
-    }
-    
-    // Caches the current text, in case the user cancels the edition
-    [self slk_cacheTextToDisk:self.textView.text];
-    
-    [self.textInputbar beginTextEditing];
-    
-    // Setting the text after calling -beginTextEditing is safer
-    [self.textView setText:text];
-    
-    [self.textView slk_scrollToCaretPositonAnimated:YES];
-    
-    // Brings up the keyboard if needed
-    [self presentKeyboard:YES];
-}
-
-- (void)didCommitTextEditing:(id)sender
-{
-    if (!self.textInputbar.isEditing) {
-        return;
-    }
-    
-    [self.textInputbar endTextEdition];
-    
-    // Clears the text and but not the undo manager
-    [self.textView slk_clearText:NO];
-}
-
-- (void)didCancelTextEditing:(id)sender
-{
-    if (!self.textInputbar.isEditing) {
-        return;
-    }
-    
-    [self.textInputbar endTextEdition];
-    
-    // Clears the text and but not the undo manager
-    [self.textView slk_clearText:NO];
-    
-    // Restores any previous cached text before entering in editing mode
-    [self slk_reloadTextView];
-}
-
-- (BOOL)canShowTypingIndicator
-{
-    // Don't show if the text is being edited or auto-completed.
-    if (self.textInputbar.isEditing || self.isAutoCompleting) {
-        return NO;
-    }
-    
-    // Don't show if the content offset is not at top (when inverted) or at bottom (when not inverted)
-    if ((self.isInverted && ![self.scrollViewProxy slk_isAtTop]) || (!self.isInverted && ![self.scrollViewProxy slk_isAtBottom])) {
-        return NO;
-    }
-    
-    return YES;
-}
-
-- (CGFloat)heightForAutoCompletionView
-{
-    return 0.0;
-}
-
-- (CGFloat)maximumHeightForAutoCompletionView
-{
-    CGFloat maxiumumHeight = SLKAutoCompletionViewDefaultHeight;
-    
-    if (self.isAutoCompleting) {
-        CGFloat scrollViewHeight = self.scrollViewHC.constant;
-        scrollViewHeight -= [self slk_topBarsHeight];
-        
-        if (scrollViewHeight < maxiumumHeight) {
-            maxiumumHeight = scrollViewHeight;
-        }
-    }
-    
-    return maxiumumHeight;
-}
-
-- (void)didPasteMediaContent:(NSDictionary *)userInfo
-{
-    // No implementation here. Meant to be overriden in subclass.
-}
-
-- (void)willRequestUndo
-{
-    NSString *title = NSLocalizedString(@"Undo Typing", nil);
-    NSString *acceptTitle = NSLocalizedString(@"Undo", nil);
-    NSString *cancelTitle = NSLocalizedString(@"Cancel", nil);
-    
-#ifdef __IPHONE_8_0
-    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
-    
-    [alertController addAction:[UIAlertAction actionWithTitle:acceptTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
-        // Clears the text but doesn't clear the undo manager
-        if (self.shakeToClearEnabled) {
-            [self.textView slk_clearText:NO];
-        }
-    }]];
-    
-    [alertController addAction:[UIAlertAction actionWithTitle:cancelTitle style:UIAlertActionStyleCancel handler:NULL]];
-    
-    [self presentViewController:alertController animated:YES completion:nil];
-#else
-    UIAlertView *alert = [UIAlertView new];
-    [alert setTitle:title];
-    [alert addButtonWithTitle:acceptTitle];
-    [alert addButtonWithTitle:cancelTitle];
-    [alert setCancelButtonIndex:1];
-    [alert setTag:kSLKAlertViewClearTextTag];
-    [alert setDelegate:self];
-    [alert show];
-#endif
-}
-
-- (void)setTextInputbarHidden:(BOOL)hidden
-{
-    [self setTextInputbarHidden:hidden animated:NO];
-}
-
-- (void)setTextInputbarHidden:(BOOL)hidden animated:(BOOL)animated
-{
-    if (self.isTextInputbarHidden == hidden) {
-        return;
-    }
-    
-    _textInputbarHidden = hidden;
-    
-    __weak typeof(self) weakSelf = self;
-    
-    void (^animations)() = ^void(){
-        
-        weakSelf.textInputbarHC.constant = hidden ? 0 : weakSelf.textInputbar.appropriateHeight;
-        
-        [weakSelf.view layoutIfNeeded];
-    };
-    
-    void (^completion)(BOOL finished) = ^void(BOOL finished){
-        if (hidden) {
-            [self dismissKeyboard:YES];
-        }
-    };
-    
-    if (animated) {
-        [UIView animateWithDuration:0.25 animations:animations completion:completion];
-    }
-    else {
-        animations();
-        completion(NO);
-    }
-}
-
-
-#pragma mark - Private Methods
-
-- (void)slk_didPanTextInputBar:(UIPanGestureRecognizer *)gesture
-{
-    // Textinput dragging isn't supported when
-    if (!self.view.window || !self.keyboardPanningEnabled ||
-        [self ignoreTextInputbarAdjustment] || self.isPresentedInPopover) {
-        return;
-    }
-    
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [self slk_handlePanGestureRecognizer:gesture];
-    });
-}
-
-- (void)slk_handlePanGestureRecognizer:(UIPanGestureRecognizer *)gesture
-{
-    // Local variables
-    static CGPoint startPoint;
-    static CGRect originalFrame;
-    static BOOL dragging = NO;
-    static BOOL presenting = NO;
-    
-    __block UIView *keyboardView = [self.textInputbar.inputAccessoryView keyboardViewProxy];
-    
-    // When no keyboard view has been detecting, let's skip any handling.
-    if (!keyboardView) {
-        return;
-    }
-    
-    // Dynamic variables
-    CGPoint gestureLocation = [gesture locationInView:self.view];
-    CGPoint gestureVelocity = [gesture velocityInView:self.view];
-    
-    CGFloat keyboardMaxY = CGRectGetHeight(SLKKeyWindowBounds());
-    CGFloat keyboardMinY = keyboardMaxY - CGRectGetHeight(keyboardView.frame);
-    
-    
-    // Skips this if it's not the expected textView.
-    // Checking the keyboard height constant helps to disable the view constraints update on iPad when the keyboard is undocked.
-    // Checking the keyboard status allows to keep the inputAccessoryView valid when still reacing the bottom of the screen.
-    if (![self.textView isFirstResponder] || (self.keyboardHC.constant == 0 && self.keyboardStatus == SLKKeyboardStatusDidHide)) {
-#if SLKBottomPanningEnabled
-        if ([gesture.view isEqual:self.scrollViewProxy]) {
-            if (gestureVelocity.y > 0) {
-                return;
-            }
-            else if ((self.isInverted && ![self.scrollViewProxy slk_isAtTop]) || (!self.isInverted && ![self.scrollViewProxy slk_isAtBottom])) {
-                return;
-            }
-        }
-        
-        presenting = YES;
-#else
-        if ([gesture.view isEqual:self.textInputbar] && gestureVelocity.y < 0) {
-            [self presentKeyboard:YES];
-        }
-        return;
-#endif
-    }
-    
-    switch (gesture.state) {
-        case UIGestureRecognizerStateBegan: {
-            
-            startPoint = CGPointZero;
-            dragging = NO;
-            
-            if (presenting) {
-                // Let's first present the keyboard without animation
-                [self presentKeyboard:NO];
-                
-                // So we can capture the keyboard's view
-                keyboardView = [self.textInputbar.inputAccessoryView keyboardViewProxy];
-                
-                originalFrame = keyboardView.frame;
-                originalFrame.origin.y = CGRectGetMaxY(self.view.frame);
-                
-                // And move the keyboard to the bottom edge
-                // TODO: Fix an occasional layout glitch when the keyboard appears for the first time.
-                keyboardView.frame = originalFrame;
-            }
-            
-            break;
-        }
-        case UIGestureRecognizerStateChanged: {
-            
-            if (CGRectContainsPoint(self.textInputbar.frame, gestureLocation) || dragging || presenting){
-                
-                if (CGPointEqualToPoint(startPoint, CGPointZero)) {
-                    startPoint = gestureLocation;
-                    dragging = YES;
-                    
-                    if (!presenting) {
-                        originalFrame = keyboardView.frame;
-                    }
-                }
-                
-                self.movingKeyboard = YES;
-                
-                CGPoint transition = CGPointMake(gestureLocation.x - startPoint.x, gestureLocation.y - startPoint.y);
-                
-                CGRect keyboardFrame = originalFrame;
-                
-                if (presenting) {
-                    keyboardFrame.origin.y += transition.y;
-                }
-                else {
-                    keyboardFrame.origin.y += MAX(transition.y, 0.0);
-                }
-                
-                // Makes sure they keyboard is always anchored to the bottom
-                if (CGRectGetMinY(keyboardFrame) < keyboardMinY) {
-                    keyboardFrame.origin.y = keyboardMinY;
-                }
-                
-                keyboardView.frame = keyboardFrame;
-                
-                
-                self.keyboardHC.constant = [self slk_appropriateKeyboardHeightFromRect:keyboardFrame];
-                self.scrollViewHC.constant = [self slk_appropriateScrollViewHeight];
-                
-                // layoutIfNeeded must be called before any further scrollView internal adjustments (content offset and size)
-                [self.view layoutIfNeeded];
-                
-                // Overrides the scrollView's contentOffset to allow following the same position when dragging the keyboard
-                CGPoint offset = _scrollViewOffsetBeforeDragging;
-                
-                if (self.isInverted) {
-                    if (!self.scrollViewProxy.isDecelerating && self.scrollViewProxy.isTracking) {
-                        self.scrollViewProxy.contentOffset = _scrollViewOffsetBeforeDragging;
-                    }
-                }
-                else {
-                    CGFloat keyboardHeightDelta = _keyboardHeightBeforeDragging-self.keyboardHC.constant;
-                    offset.y -= keyboardHeightDelta;
-                    
-                    self.scrollViewProxy.contentOffset = offset;
-                }
-            }
-            
-            break;
-        }
-        case UIGestureRecognizerStatePossible:
-        case UIGestureRecognizerStateCancelled:
-        case UIGestureRecognizerStateEnded:
-        case UIGestureRecognizerStateFailed: {
-            
-            if (!dragging) {
-                break;
-            }
-            
-            CGPoint transition = CGPointMake(0.0, fabs(gestureLocation.y - startPoint.y));
-            
-            CGRect keyboardFrame = originalFrame;
-            
-            if (presenting) {
-                keyboardFrame.origin.y = keyboardMinY;
-            }
-            
-            // The velocity can be changed to hide or show the keyboard based on the gesture
-            CGFloat minVelocity = 20.0;
-            CGFloat minDistance = CGRectGetHeight(keyboardFrame)/2.0;
-            
-            BOOL hide = (gestureVelocity.y > minVelocity) || (presenting && transition.y < minDistance) || (!presenting && transition.y > minDistance);
-            
-            if (hide) keyboardFrame.origin.y = keyboardMaxY;
-            
-            self.keyboardHC.constant = [self slk_appropriateKeyboardHeightFromRect:keyboardFrame];
-            self.scrollViewHC.constant = [self slk_appropriateScrollViewHeight];
-            
-            [UIView animateWithDuration:0.25
-                                  delay:0.0
-                                options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionBeginFromCurrentState
-                             animations:^{
-                                 [self.view layoutIfNeeded];
-                                 keyboardView.frame = keyboardFrame;
-                             }
-                             completion:^(BOOL finished) {
-                                 if (hide) {
-                                     [self dismissKeyboard:NO];
-                                 }
-                                 
-                                 // Tear down
-                                 startPoint = CGPointZero;
-                                 originalFrame = CGRectZero;
-                                 dragging = NO;
-                                 presenting = NO;
-                                 
-                                 self.movingKeyboard = NO;
-                             }];
-            
-            break;
-        }
-            
-        default:
-            break;
-    }
-}
-
-- (void)slk_didTapScrollView:(UIGestureRecognizer *)gesture
-{
-    if (!self.isPresentedInPopover && ![self ignoreTextInputbarAdjustment]) {
-        [self dismissKeyboard:YES];
-    }
-}
-
-- (void)slk_didPanTextView:(UIGestureRecognizer *)gesture
-{
-    [self presentKeyboard:YES];
-}
-
-- (void)slk_performRightAction
-{
-    NSArray *actions = [self.rightButton actionsForTarget:self forControlEvent:UIControlEventTouchUpInside];
-    
-    if (actions.count > 0 && [self canPressRightButton]) {
-        [self.rightButton sendActionsForControlEvents:UIControlEventTouchUpInside];
-    }
-}
-
-- (void)slk_postKeyboarStatusNotification:(NSNotification *)notification
-{
-    if ([self ignoreTextInputbarAdjustment] || self.isTransitioning) {
-        return;
-    }
-    
-    NSMutableDictionary *userInfo = [notification.userInfo mutableCopy];
-    
-    CGRect beginFrame = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
-    CGRect endFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
-    
-    // Fixes iOS7 oddness with inverted values on landscape orientation
-    if (!SLK_IS_IOS8_AND_HIGHER && SLK_IS_LANDSCAPE) {
-        beginFrame = SLKRectInvert(beginFrame);
-        endFrame = SLKRectInvert(endFrame);
-    }
-    
-    CGFloat keyboardHeight = CGRectGetHeight(endFrame);
-    
-    beginFrame.size.height = keyboardHeight;
-    endFrame.size.height = keyboardHeight;
-    
-    [userInfo setObject:[NSValue valueWithCGRect:beginFrame] forKey:UIKeyboardFrameBeginUserInfoKey];
-    [userInfo setObject:[NSValue valueWithCGRect:endFrame] forKey:UIKeyboardFrameEndUserInfoKey];
-    
-    NSString *name = [self slk_appropriateKeyboardNotificationName:notification];
-    [[NSNotificationCenter defaultCenter] postNotificationName:name object:self.textView userInfo:userInfo];
-}
-
-- (void)slk_enableTypingSuggestionIfNeeded
-{
-    if (![self.textView isFirstResponder]) {
-        return;
-    }
-    
-    BOOL enable = !self.isAutoCompleting;
-    
-    // Toggling autocorrect on Japanese keyboards breaks autocompletion by replacing the autocompletion prefix by an empty string.
-    // So for now, let's not disable autocorrection for Japanese.
-    if ([self.textView.textInputMode.primaryLanguage isEqualToString:@"ja-JP"]) {
-        return;
-    }
-    
-    // During text autocompletion, the iOS 8 QuickType bar is hidden and auto-correction and spell checking are disabled.
-    [self.textView setTypingSuggestionEnabled:enable];
-}
-
-- (void)slk_dismissTextInputbarIfNeeded
-{
-    if (self.keyboardHC.constant == 0) {
-        return;
-    }
-    
-    self.keyboardHC.constant = 0.0;
-    self.scrollViewHC.constant = [self slk_appropriateScrollViewHeight];
-    
-    [self slk_hideAutoCompletionViewIfNeeded];
-    
-    [self.view layoutIfNeeded];
-}
-
-- (void)slk_detectKeyboardStatesInNotification:(NSNotification *)notification
-{
-    // Tear down
-    _externalKeyboardDetected = NO;
-    _keyboardUndocked = NO;
-    
-    if (self.isMovingKeyboard) {
-        return;
-    }
-    
-    // Based on http://stackoverflow.com/a/5760910/287403
-    // We can determine if the external keyboard is showing by adding the origin.y of the target finish rect (end when showing, begin when hiding) to the inputAccessoryHeight.
-    // If it's greater(or equal) the window height, it's an external keyboard.
-    CGRect beginRect = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
-    CGRect endRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
-    
-    // Grab the base view for conversions as we don't want window coordinates in < iOS 8
-    // iOS 8 fixes the whole coordinate system issue for us, but iOS 7 doesn't rotate the app window coordinate space.
-    UIView *baseView = self.view.window.rootViewController.view;
-    
-    CGRect screenBounds = [UIScreen mainScreen].bounds;
-    
-    // Convert the main screen bounds into the correct coordinate space but ignore the origin.
-    CGRect viewBounds = [self.view convertRect:SLKKeyWindowBounds() fromView:nil];
-    viewBounds = CGRectMake(0, 0, viewBounds.size.width, viewBounds.size.height);
-    
-    // We want these rects in the correct coordinate space as well.
-    CGRect convertBegin = [baseView convertRect:beginRect fromView:nil];
-    CGRect convertEnd = [baseView convertRect:endRect fromView:nil];
-    
-    if ([notification.name isEqualToString:UIKeyboardWillShowNotification]) {
-        if (convertEnd.origin.y >= viewBounds.size.height) {
-            _externalKeyboardDetected = YES;
-        }
-    }
-    else if ([notification.name isEqualToString:UIKeyboardWillHideNotification]) {
-        // The additional logic check here (== to width) accounts for a glitch (iOS 8 only?) where the window has rotated it's coordinates
-        // but the beginRect doesn't yet reflect that. It should never cause a false positive.
-        if (convertBegin.origin.y >= viewBounds.size.height ||
-            convertBegin.origin.y == viewBounds.size.width) {
-            _externalKeyboardDetected = YES;
-        }
-    }
-    
-    if (SLK_IS_IPAD && CGRectGetMaxY(convertEnd) < CGRectGetMaxY(screenBounds)) {
-        
-        // The keyboard is undocked or split (iPad Only)
-        _keyboardUndocked = YES;
-        
-        // An external keyboard cannot be detected anymore
-        _externalKeyboardDetected = NO;
-    }
-}
-
-- (void)slk_adjustContentConfigurationIfNeeded
-{
-    UIEdgeInsets contentInset = self.scrollViewProxy.contentInset;
-    
-    // When inverted, we need to substract the top bars height (generally status bar + navigation bar's) to align the top of the
-    // scrollView correctly to its top edge.
-    if (self.inverted) {
-        contentInset.bottom = [self slk_topBarsHeight];
-        contentInset.top = contentInset.bottom > 0.0 ? 0.0 : contentInset.top;
-    }
-    else {
-        contentInset.bottom = 0.0;
-    }
-    
-    self.scrollViewProxy.contentInset = contentInset;
-    self.scrollViewProxy.scrollIndicatorInsets = contentInset;
-}
-
-- (void)slk_prepareForInterfaceTransitionWithDuration:(NSTimeInterval)duration
-{
-    self.transitioning = YES;
-    
-    [self.view layoutIfNeeded];
-    
-    if ([self.textView isFirstResponder]) {
-        [self.textView slk_scrollToCaretPositonAnimated:NO];
-    }
-    else {
-        [self.textView slk_scrollToBottomAnimated:NO];
-    }
-    
-    // Disables the flag after the rotation animation is finished
-    // Hacky but works.
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-        self.transitioning = NO;
-    });
-}
-
-
-#pragma mark - Keyboard Events
-
-- (void)didPressReturnKey:(id)sender
-{
-    if (self.textInputbar.isEditing) {
-        [self didCommitTextEditing:sender];
-    }
-    else {
-        [self slk_performRightAction];
-    }
-}
-
-- (void)didPressEscapeKey:(id)sender
-{
-    if (self.isAutoCompleting) {
-        [self cancelAutoCompletion];
-    }
-    else if (self.textInputbar.isEditing) {
-        [self didCancelTextEditing:sender];
-    }
-    
-    if ([self ignoreTextInputbarAdjustment] || ([self.textView isFirstResponder] && self.keyboardHC.constant == 0)) {
-        return;
-    }
-    
-    [self dismissKeyboard:YES];
-}
-
-- (void)didPressArrowKey:(id)sender
-{
-    [self.textView didPressAnyArrowKey:sender];
-}
-
-
-#pragma mark - Notification Events
-
-- (void)slk_willShowOrHideKeyboard:(NSNotification *)notification
-{
-    // Skips if the view isn't visible.
-    if (!self.view.window) {
-        return;
-    }
-    
-    // Skips if it is presented inside of a popover.
-    if (self.isPresentedInPopover) {
-        return;
-    }
-    
-    // Skips if textview did refresh only.
-    if (self.textView.didNotResignFirstResponder) {
-        return;
-    }
-    
-    SLKKeyboardStatus status = [self slk_keyboardStatusForNotification:notification];
-    
-    // Skips if it's the current status
-    if (self.keyboardStatus == status) {
-        return;
-    }
-    
-    // Updates and notifies about the keyboard status update
-    if ([self slk_updateKeyboardStatus:status]) {
-        // Posts custom keyboard notification, if logical conditions apply
-        [self slk_postKeyboarStatusNotification:notification];
-    }
-    
-    // Skips this it's not the expected textView and shouldn't force adjustment of the text input bar.
-    // This will also dismiss the text input bar if it's visible, and exit auto-completion mode if enabled.
-    if (![self.textView isFirstResponder]) {
-        // Detect the current first responder. If there is no first responder, we should just ignore these notifications.
-        UIResponder *currentResponder = [UIResponder slk_currentFirstResponder];
-        
-        if (!currentResponder) {
-            return;
-        }
-        else if (![self forceTextInputbarAdjustmentForResponder:currentResponder]) {
-            return [self slk_dismissTextInputbarIfNeeded];
-        }
-    }
-    
-    // Programatically stops scrolling before updating the view constraints (to avoid scrolling glitch).
-    if (status == SLKKeyboardStatusWillShow) {
-        [self.scrollViewProxy slk_stopScrolling];
-    }
-    
-    // Hides the auto-completion view if the keyboard is being dismissed.
-    if (![self.textView isFirstResponder] || status == SLKKeyboardStatusWillHide) {
-        [self slk_hideAutoCompletionViewIfNeeded];
-    }
-    
-    // Updates the height constraints' constants
-    self.keyboardHC.constant = [self slk_appropriateKeyboardHeightFromNotification:notification];
-    self.scrollViewHC.constant = [self slk_appropriateScrollViewHeight];
-    
-    
-    NSInteger curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
-    NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
-    
-    CGRect beginFrame = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
-    CGRect endFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
-    
-    void (^animations)() = ^void() {
-        // Scrolls to bottom only if the keyboard is about to show.
-        if (self.shouldScrollToBottomAfterKeyboardShows && self.keyboardStatus == SLKKeyboardStatusWillShow) {
-            if (self.isInverted) {
-                [self.scrollViewProxy slk_scrollToTopAnimated:YES];
-            }
-            else {
-                [self.scrollViewProxy slk_scrollToBottomAnimated:YES];
-            }
-        }
-    };
-    
-    // Begin and end frames are the same when the keyboard is shown during navigation controller's push animation.
-    // The animation happens in window coordinates (slides from right to left) but doesn't in the view controller's view coordinates.
-    if (!CGRectEqualToRect(beginFrame, endFrame))
-    {
-        // Only for this animation, we set bo to bounce since we want to give the impression that the text input is glued to the keyboard.
-        [self.view slk_animateLayoutIfNeededWithDuration:duration
-                                                  bounce:NO
-                                                 options:(curve<<16)|UIViewAnimationOptionLayoutSubviews|UIViewAnimationOptionBeginFromCurrentState
-                                              animations:animations
-                                              completion:NULL];
-    }
-    else {
-        animations();
-    }
-}
-
-- (void)slk_didShowOrHideKeyboard:(NSNotification *)notification
-{
-    // Skips if the view isn't visible
-    if (!self.view.window) {
-        return;
-    }
-    
-    // Skips if it is presented inside of a popover
-    if (self.isPresentedInPopover) {
-        return;
-    }
-    
-    // Skips if textview did refresh only
-    if (self.textView.didNotResignFirstResponder) {
-        return;
-    }
-    
-    SLKKeyboardStatus status = [self slk_keyboardStatusForNotification:notification];
-    
-    // Skips if it's the current status
-    if (self.keyboardStatus == status) {
-        return;
-    }
-    
-    // Updates and notifies about the keyboard status update
-    if ([self slk_updateKeyboardStatus:status]) {
-        // Posts custom keyboard notification, if logical conditions apply
-        [self slk_postKeyboarStatusNotification:notification];
-    }
-    
-    // After showing keyboard, check if the current cursor position could diplay autocompletion
-    if ([self.textView isFirstResponder] && status == SLKKeyboardStatusDidShow && !self.isAutoCompleting) {
-        
-        // Wait till the end of the current run loop
-        dispatch_async(dispatch_get_main_queue(), ^{
-            [self slk_processTextForAutoCompletion];
-        });
-    }
-    
-    // Very important to invalidate this flag after the keyboard is dismissed or presented, to start with a clean state next time.
-    self.movingKeyboard = NO;
-}
-
-- (void)slk_didPostSLKKeyboardNotification:(NSNotification *)notification
-{
-    if (![notification.object isEqual:self.textView]) {
-        return;
-    }
-    
-    // Used for debug only
-    NSLog(@"%@ %s: %@", NSStringFromClass([self class]), __FUNCTION__, notification);
-}
-
-- (void)slk_willChangeTextViewText:(NSNotification *)notification
-{
-    // Skips this it's not the expected textView.
-    if (![notification.object isEqual:self.textView] || !self.textView.window) {
-        return;
-    }
-    
-    [self textWillUpdate];
-}
-
-- (void)slk_didChangeTextViewText:(NSNotification *)notification
-{
-    // Skips this it's not the expected textView.
-    if (![notification.object isEqual:self.textView] || !self.textView.window) {
-        return;
-    }
-    
-    // Animated only if the view already appeared.
-    [self textDidUpdate:self.isViewVisible];
-    
-    // Process the text at every change, when the view is visible
-    if (self.isViewVisible) {
-        [self slk_processTextForAutoCompletion];
-    }
-}
-
-- (void)slk_didChangeTextViewContentSize:(NSNotification *)notification
-{
-    // Skips this it's not the expected textView.
-    if (![notification.object isEqual:self.textView] || !self.textView.window) {
-        return;
-    }
-    
-    // Animated only if the view already appeared.
-    [self textDidUpdate:self.isViewVisible];
-}
-
-- (void)slk_didChangeTextViewSelectedRange:(NSNotification *)notification
-{
-    // Skips this it's not the expected textView.
-    if (![notification.object isEqual:self.textView] || !self.textView.window) {
-        return;
-    }
-    
-    [self textSelectionDidChange];
-}
-
-- (void)slk_didChangeTextViewPasteboard:(NSNotification *)notification
-{
-    // Skips this if it's not the expected textView.
-    if (![self.textView isFirstResponder]) {
-        return;
-    }
-    
-    // Notifies only if the pasted item is nested in a dictionary.
-    if ([notification.userInfo isKindOfClass:[NSDictionary class]]) {
-        [self didPasteMediaContent:notification.userInfo];
-    }
-}
-
-- (void)slk_didShakeTextView:(NSNotification *)notification
-{
-    // Skips this if it's not the expected textView.
-    if (![self.textView isFirstResponder]) {
-        return;
-    }
-    
-    // Notifies of the shake gesture if undo mode is on and the text view is not empty
-    if (self.shakeToClearEnabled && self.textView.text.length > 0) {
-        [self willRequestUndo];
-    }
-}
-
-- (void)slk_willShowOrHideTypeIndicatorView:(UIView <SLKTypingIndicatorProtocol> *)typingIndicatorView
-{
-    // Skips if the typing indicator should not show. Ignores the checking if it's trying to hide.
-    if (![self canShowTypingIndicator] && typingIndicatorView.isVisible) {
-        return;
-    }
-    
-    CGFloat systemLayoutSizeHeight = [typingIndicatorView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
-    CGFloat height = typingIndicatorView.isVisible ? systemLayoutSizeHeight : 0.0;
-    
-    self.typingIndicatorViewHC.constant = height;
-    self.scrollViewHC.constant -= height;
-    
-    if (typingIndicatorView.isVisible) {
-        typingIndicatorView.hidden = NO;
-    }
-    
-    [self.view slk_animateLayoutIfNeededWithBounce:self.bounces
-                                           options:UIViewAnimationOptionCurveEaseInOut
-                                        animations:NULL
-                                        completion:^(BOOL finished) {
-                                            if (!typingIndicatorView.isVisible) {
-                                                typingIndicatorView.hidden = YES;
-                                            }
-                                        }];
-}
-
-- (void)slk_willTerminateApplication:(NSNotification *)notification
-{
-    // Caches the text before it's too late!
-    if (self.isViewVisible) {
-        [self slk_cacheTextView];
-    }
-}
-
-
-#pragma mark - KVO Events
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
-{
-    if ([object conformsToProtocol:@protocol(SLKTypingIndicatorProtocol)] && [keyPath isEqualToString:@"visible"]) {
-        [self slk_willShowOrHideTypeIndicatorView:object];
-    }
-    else {
-        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
-    }
-}
-
-
-#pragma mark - Auto-Completion Text Processing
-
-- (void)registerPrefixesForAutoCompletion:(NSArray *)prefixes
-{
-    NSMutableArray *array = [NSMutableArray arrayWithArray:self.registeredPrefixes];
-    
-    for (NSString *prefix in prefixes) {
-        // Skips if the prefix is not a valid string
-        if (![prefix isKindOfClass:[NSString class]] || prefix.length == 0) {
-            continue;
-        }
-        
-        // Adds the prefix if not contained already
-        if (![array containsObject:prefix]) {
-            [array addObject:prefix];
-        }
-    }
-    
-    if (_registeredPrefixes) {
-        _registeredPrefixes = nil;
-    }
-    
-    _registeredPrefixes = [[NSArray alloc] initWithArray:array];
-}
-
-- (void)didChangeAutoCompletionPrefix:(NSString *)prefix andWord:(NSString *)word
-{
-    // No implementation here. Meant to be overriden in subclass.
-}
-
-- (BOOL)canShowAutoCompletion
-{
-    // Let's keep this around for a bit, for backwards compatibility.
-    return NO;
-}
-
-- (void)showAutoCompletionView:(BOOL)show
-{
-    // Reloads the tableview before showing/hiding
-    if (show) {
-        [self.autoCompletionView reloadData];
-    }
-    
-    self.autoCompleting = show;
-    
-    // Toggles auto-correction if requiered
-    [self slk_enableTypingSuggestionIfNeeded];
-    
-    CGFloat viewHeight = show ? [self heightForAutoCompletionView] : 0.0;
-    
-    if (self.autoCompletionViewHC.constant == viewHeight) {
-        return;
-    }
-    
-    // If the auto-completion view height is bigger than the maximum height allows, it is reduce to that size. Default 140 pts.
-    CGFloat maximumHeight = [self maximumHeightForAutoCompletionView];
-    
-    if (viewHeight > maximumHeight) {
-        viewHeight = maximumHeight;
-    }
-    
-    CGFloat contentViewHeight = self.scrollViewHC.constant + self.autoCompletionViewHC.constant;
-    
-    // On iPhone, the auto-completion view can't extend beyond the content view height
-    if (SLK_IS_IPHONE && viewHeight > contentViewHeight) {
-        viewHeight = contentViewHeight;
-    }
-    
-    self.autoCompletionViewHC.constant = viewHeight;
-    
-    [self.view slk_animateLayoutIfNeededWithBounce:self.bounces
-                                           options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionLayoutSubviews|UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionAllowUserInteraction
-                                        animations:NULL];
-}
-
-- (void)acceptAutoCompletionWithString:(NSString *)string
-{
-    [self acceptAutoCompletionWithString:string keepPrefix:YES];
-}
-
-- (void)acceptAutoCompletionWithString:(NSString *)string keepPrefix:(BOOL)keepPrefix
-{
-    if (string.length == 0) {
-        return;
-    }
-    
-    SLKTextView *textView = self.textView;
-    
-    NSUInteger location = self.foundPrefixRange.location;
-    if (keepPrefix) {
-        location += self.foundPrefixRange.length;
-    }
-    
-    NSUInteger length = self.foundWord.length;
-    if (!keepPrefix) {
-        length += self.foundPrefixRange.length;
-    }
-    
-    NSRange range = NSMakeRange(location, length);
-    NSRange insertionRange = [textView slk_insertText:string inRange:range];
-    
-    textView.selectedRange = NSMakeRange(insertionRange.location, 0);
-    
-    [self cancelAutoCompletion];
-    
-    [textView slk_scrollToCaretPositonAnimated:NO];
-}
-
-- (void)cancelAutoCompletion
-{
-    [self slk_invalidateAutoCompletion];
-    [self slk_hideAutoCompletionViewIfNeeded];
-}
-
-- (void)slk_processTextForAutoCompletion
-{
-    if (self.isTransitioning) {
-        return;
-    }
-    
-    // Avoids text processing for auto-completion if the registered prefix list is empty.
-    if (self.registeredPrefixes.count == 0) {
-        return;
-    }
-    
-    NSString *text = self.textView.text;
-    
-    // Skip, when there is no text to process
-    if (text.length == 0) {
-        return [self cancelAutoCompletion];
-    }
-    
-    NSRange range;
-    NSString *word = [self.textView slk_wordAtCaretRange:&range];
-    
-    [self slk_invalidateAutoCompletion];
-    
-    if (word.length > 0) {
-        
-        for (NSString *prefix in self.registeredPrefixes) {
-            if ([word hasPrefix:prefix]) {
-                // Captures the detected symbol prefix
-                _foundPrefix = prefix;
-                
-                // Used later for replacing the detected range with a new string alias returned in -acceptAutoCompletionWithString:
-                _foundPrefixRange = NSMakeRange(range.location, prefix.length);
-            }
-        }
-    }
-    
-    [self slk_handleProcessedWord:word range:range];
-}
-
-- (void)slk_handleProcessedWord:(NSString *)word range:(NSRange)range
-{
-    // Cancel auto-completion if the cursor is placed before the prefix
-    if (self.textView.selectedRange.location <= self.foundPrefixRange.location) {
-        return [self cancelAutoCompletion];
-    }
-    
-    if (self.foundPrefix.length > 0) {
-        if (range.length == 0 || range.length != word.length) {
-            return [self cancelAutoCompletion];
-        }
-        
-        if (word.length > 0) {
-            // Removes the found prefix
-            _foundWord = [word substringFromIndex:self.foundPrefix.length];
-            
-            // If the prefix is still contained in the word, cancels
-            if ([self.foundWord rangeOfString:self.foundPrefix].location != NSNotFound) {
-                return [self cancelAutoCompletion];
-            }
-        }
-        else {
-            return [self cancelAutoCompletion];
-        }
-    }
-    else {
-        return [self cancelAutoCompletion];
-    }
-    
-    [self didChangeAutoCompletionPrefix:self.foundPrefix andWord:self.foundWord];
-}
-
-- (void)slk_invalidateAutoCompletion
-{
-    _foundPrefix = nil;
-    _foundWord = nil;
-    _foundPrefixRange = NSMakeRange(0, 0);
-    
-    [self.autoCompletionView setContentOffset:CGPointZero];
-}
-
-- (void)slk_hideAutoCompletionViewIfNeeded
-{
-    if (self.isAutoCompleting) {
-        [self showAutoCompletionView:NO];
-    }
-}
-
-
-#pragma mark - Text Caching
-
-- (NSString *)keyForTextCaching
-{
-    // No implementation here. Meant to be overriden in subclass.
-    return nil;
-}
-
-- (NSString *)slk_keyForPersistency
-{
-    NSString *key = [self keyForTextCaching];
-    if (key == nil) {
-        return nil;
-    }
-    return [NSString stringWithFormat:@"%@.%@", SLKTextViewControllerDomain, key];
-}
-
-- (void)slk_reloadTextView
-{
-    NSString *key = [self slk_keyForPersistency];
-    if (key == nil) {
-        return;
-    }
-    NSString *cachedText = [[NSUserDefaults standardUserDefaults] objectForKey:key];
-    
-    if (self.textView.text.length == 0 || cachedText.length > 0) {
-        self.textView.text = cachedText;
-    }
-}
-
-- (void)slk_cacheTextView
-{
-    [self slk_cacheTextToDisk:self.textView.text];
-}
-
-- (void)clearCachedText
-{
-    [self slk_cacheTextToDisk:nil];
-}
-
-- (void)slk_cacheTextToDisk:(NSString *)text
-{
-    NSString *key = [self slk_keyForPersistency];
-    
-    if (!key || key.length == 0) {
-        return;
-    }
-    
-    NSString *cachedText = [[NSUserDefaults standardUserDefaults] objectForKey:key];
-    
-    // Caches text only if its a valid string and not already cached
-    if (text.length > 0 && ![text isEqualToString:cachedText]) {
-        [[NSUserDefaults standardUserDefaults] setObject:text forKey:key];
-    }
-    // Clears cache only if it exists
-    else if (text.length == 0 && cachedText.length > 0) {
-        [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
-    }
-    else {
-        // Skips so it doesn't hit 'synchronize' unnecessarily
-        return;
-    }
-    
-    [[NSUserDefaults standardUserDefaults] synchronize];
-}
-
-+ (void)clearAllCachedText
-{
-    NSMutableArray *cachedKeys = [NSMutableArray new];
-    
-    for (NSString *key in [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]) {
-        if ([key rangeOfString:SLKTextViewControllerDomain].location != NSNotFound) {
-            [cachedKeys addObject:key];
-        }
-    }
-    
-    if (cachedKeys.count == 0) {
-        return;
-    }
-    
-    for (NSString *cachedKey in cachedKeys) {
-        [[NSUserDefaults standardUserDefaults] removeObjectForKey:cachedKey];
-    }
-    
-    [[NSUserDefaults standardUserDefaults] synchronize];
-}
-
-
-#pragma mark - Customization
-
-- (void)registerClassForTextView:(Class)aClass
-{
-    if (aClass == nil) {
-        return;
-    }
-    
-    NSAssert([aClass isSubclassOfClass:[SLKTextView class]], @"The registered class is invalid, it must be a subclass of SLKTextView.");
-    self.textViewClass = aClass;
-}
-
-- (void)registerClassForTypingIndicatorView:(Class)aClass
-{
-    if (aClass == nil) {
-        return;
-    }
-    
-    NSAssert([aClass isSubclassOfClass:[UIView class]], @"The registered class is invalid, it must be a subclass of UIView.");
-    self.typingIndicatorViewClass = aClass;
-}
-
-
-#pragma mark - UITextViewDelegate Methods
-
-- (BOOL)textView:(SLKTextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
-{
-    if (![textView isKindOfClass:[SLKTextView class]]) {
-        return YES;
-    }
-    
-    BOOL newWordInserted = ([text rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].location != NSNotFound);
-    
-    // It should not change if auto-completion is active and trying to replace with an auto-correction suggested text.
-    if (self.isAutoCompleting && text.length > 1) {
-        return NO;
-    }
-    
-    // Records text for undo for every new word
-    if (newWordInserted) {
-        [textView slk_prepareForUndo:@"Word Change"];
-    }
-    
-    // Detects double spacebar tapping, to replace the default "." insert with a formatting symbol, if needed.
-    if (textView.autoCompleteFormatting && range.location > 0 && [text length] > 0 &&
-        [[NSCharacterSet whitespaceCharacterSet] characterIsMember:[text characterAtIndex:0]] &&
-        [[NSCharacterSet whitespaceCharacterSet] characterIsMember:[textView.text characterAtIndex:range.location - 1]]) {
-        
-        BOOL shouldChange = YES;
-        
-        NSRange wordRange = range;
-        wordRange.location -= 2; // minus the white space added with the double space bar tapping
-        
-        NSArray *symbols = textView.registeredSymbols;
-        
-        NSMutableCharacterSet *invalidCharacters = [NSMutableCharacterSet new];
-        [invalidCharacters formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
-        [invalidCharacters formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
-        [invalidCharacters removeCharactersInString:[symbols componentsJoinedByString:@""]];
-        
-        for (NSString *symbol in symbols) {
-            
-            // Detects the closest registered symbol to the caret, from right to left
-            NSRange searchRange = NSMakeRange(0, wordRange.location);
-            NSRange prefixRange = [textView.text rangeOfString:symbol options:NSBackwardsSearch range:searchRange];
-            
-            if (prefixRange.location == NSNotFound) {
-                continue;
-            }
-            
-            NSRange nextCharRange = NSMakeRange(prefixRange.location+1, 1);
-            NSString *charAfterSymbol = [textView.text substringWithRange:nextCharRange];
-            
-            if (prefixRange.location != NSNotFound && ![invalidCharacters characterIsMember:[charAfterSymbol characterAtIndex:0]]) {
-                
-                if ([self textView:textView shouldInsertSuffixForFormattingWithSymbol:symbol prefixRange:prefixRange]) {
-                    
-                    NSRange suffixRange;
-                    [textView slk_wordAtRange:wordRange rangeInText:&suffixRange];
-                    
-                    // Skip if the detected word already has a suffix
-                    if ([[textView.text substringWithRange:suffixRange] hasSuffix:symbol]) {
-                        continue;
-                    }
-                    
-                    suffixRange.location += suffixRange.length;
-                    suffixRange.length = 0;
-                    
-                    NSString *lastCharacter = [textView.text substringWithRange:NSMakeRange(suffixRange.location, 1)];
-                    
-                    // Checks if the last character was a line break, so we append the symbol in the next line too
-                    if ([[NSCharacterSet newlineCharacterSet] characterIsMember:[lastCharacter characterAtIndex:0]]) {
-                        suffixRange.location += 1;
-                    }
-                    
-                    [textView slk_insertText:symbol inRange:suffixRange];
-                    shouldChange = NO;
-                    
-                    break; // exit
-                }
-            }
-        }
-        
-        return shouldChange;
-    }
-    else if ([text isEqualToString:@"\n"]) {
-        //Detected break. Should insert new line break programatically instead.
-        [textView slk_insertNewLineBreak];
-        
-        return NO;
-    }
-    else {
-        NSDictionary *userInfo = @{@"text": text, @"range": [NSValue valueWithRange:range]};
-        [[NSNotificationCenter defaultCenter] postNotificationName:SLKTextViewTextWillChangeNotification object:self.textView userInfo:userInfo];
-        
-        return YES;
-    }
-}
-
-- (void)textViewDidChange:(SLKTextView *)textView
-{
-    // Keep to avoid unnecessary crashes. Was meant to be overriden in subclass while calling super.
-}
-
-- (void)textViewDidChangeSelection:(SLKTextView *)textView
-{
-    // Keep to avoid unnecessary crashes. Was meant to be overriden in subclass while calling super.
-}
-
-- (BOOL)textViewShouldBeginEditing:(SLKTextView *)textView
-{
-    return YES;
-}
-
-- (BOOL)textViewShouldEndEditing:(SLKTextView *)textView
-{
-    return YES;
-}
-
-- (void)textViewDidBeginEditing:(SLKTextView *)textView
-{
-    // No implementation here. Meant to be overriden in subclass.
-}
-
-- (void)textViewDidEndEditing:(SLKTextView *)textView
-{
-    // No implementation here. Meant to be overriden in subclass.
-}
-
-
-#pragma mark - SLKTextViewDelegate Methods
-
-- (BOOL)textView:(SLKTextView *)textView shouldOfferFormattingForSymbol:(NSString *)symbol
-{
-    return YES;
-}
-
-- (BOOL)textView:(SLKTextView *)textView shouldInsertSuffixForFormattingWithSymbol:(NSString *)symbol prefixRange:(NSRange)prefixRange
-{
-    if (prefixRange.location > 0) {
-        NSRange previousCharRange = NSMakeRange(prefixRange.location-1, 1);
-        NSString *previousCharacter = [self.textView.text substringWithRange:previousCharRange];
-        
-        // Only insert a suffix if the character before the prefix was a whitespace or a line break
-        if ([previousCharacter rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].location != NSNotFound) {
-            return YES;
-        }
-        else {
-            return NO;
-        }
-    }
-    
-    return YES;
-}
-
-
-#pragma mark - UITableViewDataSource Methods
-
-- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-{
-    return 0;
-}
-
-- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-{
-    return nil;
-}
-
-
-#pragma mark - UICollectionViewDataSource Methods
-
-- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
-{
-    return 0;
-}
-
-- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
-{
-    return nil;
-}
-
-
-#pragma mark - UIScrollViewDelegate Methods
-
-- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
-{
-    if (!self.scrollViewProxy.scrollsToTop || self.keyboardStatus == SLKKeyboardStatusWillShow) {
-        return NO;
-    }
-    
-    if (self.isInverted) {
-        [self.scrollViewProxy slk_scrollToBottomAnimated:YES];
-        return NO;
-    }
-    else {
-        return YES;
-    }
-}
-
-- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
-{
-    self.movingKeyboard = NO;
-}
-
-- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
-{
-    self.movingKeyboard = NO;
-}
-
-- (void)scrollViewDidScroll:(UIScrollView *)scrollView
-{
-    if ([scrollView isEqual:self.autoCompletionView]) {
-        CGRect frame = self.autoCompletionHairline.frame;
-        frame.origin.y = scrollView.contentOffset.y;
-        self.autoCompletionHairline.frame = frame;
-    }
-    else {
-        if (!self.isMovingKeyboard) {
-            _scrollViewOffsetBeforeDragging = scrollView.contentOffset;
-            _keyboardHeightBeforeDragging = self.keyboardHC.constant;
-        }
-    }
-}
-
-
-#pragma mark - UIGestureRecognizerDelegate Methods
-
-- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gesture
-{
-    if ([gesture isEqual:self.singleTapGesture]) {
-        return [self.textView isFirstResponder] && ![self ignoreTextInputbarAdjustment];
-    }
-    else if ([gesture isEqual:self.verticalPanGesture]) {
-        return self.keyboardPanningEnabled && ![self ignoreTextInputbarAdjustment];
-    }
-    
-    return NO;
-}
-
-
-#pragma mark - UIAlertViewDelegate Methods
-
-- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
-{
-    if (alertView.tag != kSLKAlertViewClearTextTag || buttonIndex == [alertView cancelButtonIndex] ) {
-        return;
-    }
-    
-    // Clears the text but doesn't clear the undo manager
-    if (self.shakeToClearEnabled) {
-        [self.textView slk_clearText:NO];
-    }
-}
-
-
-#pragma mark - View Auto-Layout
-
-- (void)slk_setupViewConstraints
-{
-    NSDictionary *views = @{@"scrollView": self.scrollViewProxy,
-                            @"autoCompletionView": self.autoCompletionView,
-                            @"typingIndicatorView": self.typingIndicatorProxyView,
-                            @"textInputbar": self.textInputbar,
-                            };
-    
-    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView(0@750)][autoCompletionView(0@750)][typingIndicatorView(0)]-0@999-[textInputbar(0)]-0-|" options:0 metrics:nil views:views]];
-    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:nil views:views]];
-    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[autoCompletionView]|" options:0 metrics:nil views:views]];
-    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[typingIndicatorView]|" options:0 metrics:nil views:views]];
-    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[textInputbar]|" options:0 metrics:nil views:views]];
-    
-    self.scrollViewHC = [self.view slk_constraintForAttribute:NSLayoutAttributeHeight firstItem:self.scrollViewProxy secondItem:nil];
-    self.autoCompletionViewHC = [self.view slk_constraintForAttribute:NSLayoutAttributeHeight firstItem:self.autoCompletionView secondItem:nil];
-    self.typingIndicatorViewHC = [self.view slk_constraintForAttribute:NSLayoutAttributeHeight firstItem:self.typingIndicatorProxyView secondItem:nil];
-    self.textInputbarHC = [self.view slk_constraintForAttribute:NSLayoutAttributeHeight firstItem:self.textInputbar secondItem:nil];
-    self.keyboardHC = [self.view slk_constraintForAttribute:NSLayoutAttributeBottom firstItem:self.view secondItem:self.textInputbar];
-    
-    [self slk_updateViewConstraints];
-}
-
-- (void)slk_updateViewConstraints
-{
-    self.textInputbarHC.constant = self.textInputbar.minimumInputbarHeight;
-    self.scrollViewHC.constant = [self slk_appropriateScrollViewHeight];
-    self.keyboardHC.constant = [self slk_appropriateKeyboardHeightFromRect:CGRectNull];
-    
-    if (self.textInputbar.isEditing) {
-        self.textInputbarHC.constant += self.textInputbar.editorContentViewHeight;
-    }
-    
-    [super updateViewConstraints];
-}
-
-
-#pragma mark - External Keyboard Support
-
-- (NSArray *)keyCommands
-{
-    NSMutableArray *keyboardCommands = [NSMutableArray new];
-    
-    [keyboardCommands addObject:[self slk_returnKeyCommand]];
-    [keyboardCommands addObject:[self slk_escKeyCommand]];
-    [keyboardCommands addObject:[self slk_arrowKeyCommand:UIKeyInputUpArrow]];
-    [keyboardCommands addObject:[self slk_arrowKeyCommand:UIKeyInputDownArrow]];
-    
-    return keyboardCommands;
-}
-
-- (UIKeyCommand *)slk_returnKeyCommand
-{
-    UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:0 action:@selector(didPressReturnKey:)];
-    
-#ifdef __IPHONE_9_0
-    if ([UIKeyCommand respondsToSelector:@selector(keyCommandWithInput:modifierFlags:action:discoverabilityTitle:)] ) {
-        // Only available since iOS 9
-        if (self.textInputbar.isEditing) {
-            command.discoverabilityTitle = [self.textInputbar.editorRightButton titleForState:UIControlStateNormal] ? : NSLocalizedString(@"Commit Editing", nil);
-        }
-        else if (self.textView.text.length > 0) {
-            command.discoverabilityTitle = [self.rightButton titleForState:UIControlStateNormal] ? : NSLocalizedString(@"Send", nil);
-        }
-    }
-#endif
-    
-    return command;
-}
-
-- (UIKeyCommand *)slk_escKeyCommand
-{
-    UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:UIKeyInputEscape modifierFlags:0 action:@selector(didPressEscapeKey:)];
-    
-#ifdef __IPHONE_9_0
-    if ([UIKeyCommand respondsToSelector:@selector(keyCommandWithInput:modifierFlags:action:discoverabilityTitle:)] ) {
-        // Only available since iOS 9
-        if (self.isAutoCompleting) {
-            command.discoverabilityTitle = NSLocalizedString(@"Exit Auto-Completion", nil);
-        }
-        else if (self.textInputbar.isEditing) {
-            command.discoverabilityTitle = [self.textInputbar.editorRightButton titleForState:UIControlStateNormal] ? : NSLocalizedString(@"Exit Editing", nil);
-        }
-        else if (!self.isExternalKeyboardDetected && self.keyboardHC.constant != 0) {
-            command.discoverabilityTitle = NSLocalizedString(@"Hide Keyboard", nil);
-        }
-    }
-#endif
-    
-    return command;
-}
-
-- (UIKeyCommand *)slk_arrowKeyCommand:(NSString *)inputUpArrow
-{
-    UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:inputUpArrow modifierFlags:0 action:@selector(didPressArrowKey:)];
-    
-#ifdef __IPHONE_9_0
-    // Only available since iOS 9
-    if ([UIKeyCommand respondsToSelector:@selector(keyCommandWithInput:modifierFlags:action:discoverabilityTitle:)] ) {
-        if ([inputUpArrow isEqualToString:UIKeyInputUpArrow]) {
-            command.discoverabilityTitle = NSLocalizedString(@"Move Up", nil);
-        }
-        if ([inputUpArrow isEqualToString:UIKeyInputDownArrow]) {
-            command.discoverabilityTitle = NSLocalizedString(@"Move Down", nil);
-        }
-    }
-#endif
-    
-    return command;
-}
-
-
-#pragma mark - NSNotificationCenter register/unregister
-
-- (void)slk_registerNotifications
-{
-    [self slk_unregisterNotifications];
-    
-    // Keyboard notifications
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_willShowOrHideKeyboard:) name:UIKeyboardWillShowNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_willShowOrHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didShowOrHideKeyboard:) name:UIKeyboardDidShowNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didShowOrHideKeyboard:) name:UIKeyboardDidHideNotification object:nil];
-    
-#if SLK_KEYBOARD_NOTIFICATION_DEBUG
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didPostSLKKeyboardNotification:) name:SLKKeyboardWillShowNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didPostSLKKeyboardNotification:) name:SLKKeyboardDidShowNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didPostSLKKeyboardNotification:) name:SLKKeyboardWillHideNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didPostSLKKeyboardNotification:) name:SLKKeyboardDidHideNotification object:nil];
-#endif
-    
-    // TextView notifications
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_willChangeTextViewText:) name:SLKTextViewTextWillChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didChangeTextViewText:) name:UITextViewTextDidChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didChangeTextViewContentSize:) name:SLKTextViewContentSizeDidChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didChangeTextViewSelectedRange:) name:SLKTextViewSelectedRangeDidChangeNotification object:nil];
-    
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didChangeTextViewPasteboard:) name:SLKTextViewDidPasteItemNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_didShakeTextView:) name:SLKTextViewDidShakeNotification object:nil];
-    
-    // Application notifications
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_willTerminateApplication:) name:UIApplicationWillTerminateNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(slk_willTerminateApplication:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
-}
-
-- (void)slk_unregisterNotifications
-{
-    // Keyboard notifications
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
-    
-#if SLK_KEYBOARD_NOTIFICATION_DEBUG
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKKeyboardWillShowNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKKeyboardDidShowNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKKeyboardWillHideNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKKeyboardDidHideNotification object:nil];
-#endif
-    
-    // TextView notifications
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidBeginEditingNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidEndEditingNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKTextViewTextWillChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKTextViewContentSizeDidChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKTextViewSelectedRangeDidChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKTextViewDidPasteItemNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:SLKTextViewDidShakeNotification object:nil];
-    
-    // Application notifications
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
-}
-
-
-#pragma mark - View Auto-Rotation
-
-#ifdef __IPHONE_8_0
-- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
-{
-    [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
-}
-
-- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
-{
-    [self slk_prepareForInterfaceTransitionWithDuration:coordinator.transitionDuration];
-    
-    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
-}
-#else
-- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
-{
-    if ([self respondsToSelector:@selector(viewWillTransitionToSize:withTransitionCoordinator:)]) {
-        return;
-    }
-    
-    [self slk_prepareForInterfaceTransitionWithDuration:duration];
-}
-#endif
-
-#ifdef __IPHONE_9_0
-- (UIInterfaceOrientationMask)supportedInterfaceOrientations
-#else
-- (NSUInteger)supportedInterfaceOrientations
-#endif
-{
-    return UIInterfaceOrientationMaskAll;
-}
-
-- (BOOL)shouldAutorotate
-{
-    return YES;
-}
-
-
-#pragma mark - View lifeterm
-
-- (void)didReceiveMemoryWarning
-{
-    [super didReceiveMemoryWarning];
-}
-
-- (void)dealloc
-{
-    _tableView.delegate = nil;
-    _tableView.dataSource = nil;
-    _tableView = nil;
-    
-    _collectionView.delegate = nil;
-    _collectionView.dataSource = nil;
-    _collectionView = nil;
-    
-    _scrollView = nil;
-    
-    _autoCompletionView.delegate = nil;
-    _autoCompletionView.dataSource = nil;
-    _autoCompletionView = nil;
-    
-    _textInputbar.textView.delegate = nil;
-    _textInputbar = nil;
-    _textViewClass = nil;
-    
-    [_typingIndicatorProxyView removeObserver:self forKeyPath:@"visible"];
-    _typingIndicatorProxyView = nil;
-    _typingIndicatorViewClass = nil;
-    
-    _registeredPrefixes = nil;
-    _singleTapGesture.delegate = nil;
-    _singleTapGesture = nil;
-    _verticalPanGesture.delegate = nil;
-    _verticalPanGesture = nil;
-    _scrollViewHC = nil;
-    _textInputbarHC = nil;
-    _typingIndicatorViewHC = nil;
-    _autoCompletionViewHC = nil;
-    _keyboardHC = nil;
-    
-    [self slk_unregisterNotifications];
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/usergrid/blob/c638c774/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTypingIndicatorProtocol.h
----------------------------------------------------------------------
diff --git a/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTypingIndicatorProtocol.h b/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTypingIndicatorProtocol.h
deleted file mode 100644
index 7b2deae..0000000
--- a/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTypingIndicatorProtocol.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-//   Copyright 2014 Slack Technologies, Inc.
-//
-//   Licensed under the Apache License, Version 2.0 (the "License");
-//   you may not use this file except in compliance with the License.
-//   You may obtain a copy of the License at
-//
-//       http://www.apache.org/licenses/LICENSE-2.0
-//
-//   Unless required by applicable law or agreed to in writing, software
-//   distributed under the License is distributed on an "AS IS" BASIS,
-//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//   See the License for the specific language governing permissions and
-//   limitations under the License.
-//
-
-#import <Foundation/Foundation.h>
-
-/** Generic protocol needed when customizing your own typing indicator view. */
-@protocol SLKTypingIndicatorProtocol <NSObject>
-@required
-
-/**
- Returns YES if the indicator is visible.
- SLKTextViewController depends on this property internally, by observing its value changes to update the typing indicator view's constraints automatically.
- You can simply @synthesize this property to make it KVO compliant, or override its setter method and wrap its implementation with -willChangeValueForKey: and -didChangeValueForKey: methods, for more complex KVO compliance.
- */
-@property (nonatomic, getter = isVisible) BOOL visible;
-
-@optional
-
-/**
- Dismisses the indicator view.
- */
-- (void)dismissIndicator;
-
-@end
\ No newline at end of file