  */
 extension UIView {
     
+    private struct ToastKeys {
+        static var Timer        = "CSToastTimerKey"
+        static var Duration     = "CSToastDurationKey"
+        static var Position     = "CSToastPositionKey"
+        static var Completion   = "CSToastCompletionKey"
+        static var ActiveToast  = "CSToastActiveToastKey"
+        static var ActivityView = "CSToastActivityViewKey"
+        static var Queue        = "CSToastQueueKey"
+    }
+    
+    private class ToastCompletionWrapper {
+        var completion: ((Bool) -> Void)?
+        
+        init(_ completion: ((Bool) -> Void)?) {
+            self.completion = completion
+        }
+    }
+    
+    private enum ToastError: ErrorType {
+        case InsufficientData
+    }
+    
+    private var queue: NSMutableArray {
+        get {
+            if let queue = objc_getAssociatedObject(self, &ToastKeys.Queue) as? NSMutableArray {
+                return queue
+            } else {
+                let queue = NSMutableArray()
+                objc_setAssociatedObject(self, &ToastKeys.Queue, queue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+                return queue
+            }
+        }
+    }
+    
     // MARK: - Make Toast Methods
     
     func makeToast(message: String) {

    
    // MARK: - Helpers

    private func centerPointForPosition(position: ToastPosition, toast: UIView, style: ToastStyle) -> CGPoint {
        switch(position) {
        case .Top:
            return CGPoint(x: self.bounds.size.width / 2.0, y: (toast.frame.size.height / 2.0) + style.verticalPadding)
        case .Center:
            return CGPoint(x: self.bounds.size.width / 2.0, y: self.bounds.size.height / 2.0)
        case .Bottom:
            return CGPoint(x: self.bounds.size.width / 2.0, y: (self.bounds.size.height - (toast.frame.size.height / 2.0)) - style.verticalPadding)
        }
    }
}

    // MARK: - Show Toast Methods
    
    func showToast(toast: UIView) {
        self.showToast(toast, duration: ToastManager.shared.duration, position: ToastManager.shared.position, completion: nil)
    }
    
    func showToast(toast: UIView, duration: NSTimeInterval, position: ToastPosition, completion: ((didTap: Bool) -> Void)?) {
        let point = self.centerPointForPosition(position, toast: toast)
        self.showToast(toast, duration: duration, position: point, completion: completion)
    }
    
    func showToast(toast: UIView, duration: NSTimeInterval, position: CGPoint, completion: ((didTap: Bool) -> Void)?) {
        objc_setAssociatedObject(toast, &ToastKeys.Completion, ToastCompletionWrapper(completion), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        if let _ = objc_getAssociatedObject(self, &ToastKeys.Queue) where ToastManager.shared.queueEnabled {
            objc_setAssociatedObject(toast, &ToastKeys.Duration, NSNumber(double: duration), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            objc_setAssociatedObject(toast, &ToastKeys.Position, NSValue(CGPoint: position), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            
            self.queue.addObject(toast)
        } else {
            self.showToast(toast, duration: duration, position: position)
        }
    }
    
    // MARK: - Private Show/Hide Methods
    
    private func showToast(toast: UIView, duration: NSTimeInterval, position: CGPoint) {
        toast.center = position
        toast.alpha = 0.0
        
        if ToastManager.shared.tapToDismissEnabled {
            let recognizer = UITapGestureRecognizer(target: self, action: "handleToastTapped:")
            toast.addGestureRecognizer(recognizer)
            toast.userInteractionEnabled = true
            toast.exclusiveTouch = true
        }
        
        objc_setAssociatedObject(self, &ToastKeys.ActiveToast, toast, .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        self.addSubview(toast)
        
        UIView.animateWithDuration(ToastManager.shared.duration, delay: 0.0, options: [.CurveEaseOut, .AllowUserInteraction], animations: { () -> Void in
            toast.alpha = 1.0
        }) { (Bool finished) -> Void in
            let timer = NSTimer(timeInterval: duration, target: self, selector: "toastTimerDidFinish:", userInfo: toast, repeats: false)
            NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
            objc_setAssociatedObject(toast, &ToastKeys.Timer, timer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    private func hideToast(toast: UIView) {
        self.hideToast(toast, fromTap: false)
    }
    
    private func hideToast(toast: UIView, fromTap: Bool) {
        
        UIView.animateWithDuration(ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.CurveEaseIn, .BeginFromCurrentState], animations: { () -> Void in
            toast.alpha = 0.0
        }) { (didFinish: Bool) -> Void in
            toast.removeFromSuperview()
            
            objc_setAssociatedObject(self, &ToastKeys.ActiveToast, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            
            if let wrapper = objc_getAssociatedObject(toast, &ToastKeys.Completion) as? ToastCompletionWrapper, completion = wrapper.completion {
                completion(fromTap)
            }
            
            if let nextToast = self.queue.firstObject as? UIView, duration = objc_getAssociatedObject(nextToast, &ToastKeys.Duration) as? NSNumber, position = objc_getAssociatedObject(nextToast, &ToastKeys.Position) as? NSValue {
                self.queue.removeObjectAtIndex(0)
                self.showToast(nextToast, duration: duration.doubleValue, position: position.CGPointValue())
            }
        }
    }
    
    // MARK: - Events
    
    func handleToastTapped(recognizer: UITapGestureRecognizer) {
        if let toast = recognizer.view, timer = objc_getAssociatedObject(toast, &ToastKeys.Timer) as? NSTimer {
            timer.invalidate()
            self.hideToast(toast, fromTap: true)
        }
    }
    
    func toastTimerDidFinish(timer: NSTimer) {
        if let toast = timer.userInfo as? UIView {
            self.hideToast(toast)
        }
    }
    
    // MARK: - Toast Construction
