     guard let cv = collectionView else {
       return CGRectZero
     }
-
+    
     let position = positionForIndexPath(indexPath)
     let aCellSize = sizeForCellAtIndexPath(indexPath)
     let padding: CGFloat
     let contentRect = UIEdgeInsetsInsetRect(cv.frame, cv.contentInset)
     let result: CGRect
-
+    
     switch scrollDirection {
     case .Vertical:
       let width = CGRectGetWidth(contentRect)

      unboundIndexStart = Int(rect.origin.x / cellSize.width)
      length = UInt(rect.size.width / cellSize.width) + 1
    }

    let unboundIndexEnd: Int = unboundIndexStart + Int(length)

    if preemptivelyRenderLayout {
      insertCellsToUnboundIndex(Int.max)
    }

    else {
      insertCellsToUnboundIndex(unboundIndexEnd)
    }

    var attributes = Set<UICollectionViewLayoutAttributes>()

    // O(n^2)
    for unboundIndex in unboundIndexStart..<unboundIndexEnd {
      for boundIndex in 0..<maximumNumberOfCellsInBounds {
        var position = CGPointZero

        switch scrollDirection {
        case .Vertical:
          position = CGPoint(x: CGFloat(boundIndex), y: CGFloat(unboundIndex))
        case .Horizontal:
          position = CGPoint(x: CGFloat(unboundIndex), y: CGFloat(boundIndex))
        }

        if let indexPath = self.indexPathForPosition(position),
          let attribute = self.layoutAttributesForItemAtIndexPath(indexPath) {
            attributes.insert(attribute)
        }
      }
    }

    // Cache the attributes
    layoutAttributesCache = Array(attributes)

    return layoutAttributesCache
  }

  override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
    let frame: CGRect
    let attributes: UICollectionViewLayoutAttributes

    frame = rectForIndexPath(indexPath)
    attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
    attributes.frame = UIEdgeInsetsInsetRect(frame, insets)
    
    return attributes
  }
  
  override func prepareLayout() {
    super.prepareLayout()
    
    let scrollFrame = CGRect(
      x: collectionView!.contentOffset.x,
      y: collectionView!.contentOffset.y,
      width: collectionView!.frame.size.width,
      height: collectionView!.frame.size.height
    )
    
    let unboundIndex: Int
    switch scrollDirection {
    case .Vertical:
      unboundIndex = Int((CGRectGetMaxY(scrollFrame) / cellSize.height) + 1)
      
    case .Horizontal:
      unboundIndex = Int((CGRectGetMaxX(scrollFrame) / cellSize.width) + 1)
    }
    
    if preemptivelyRenderLayout {
      insertCellsToUnboundIndex(Int.max)
    }
      
    else {
      insertCellsToUnboundIndex(unboundIndex)
    }
  }
  
  override func prepareForCollectionViewUpdates(updateItems: [UICollectionViewUpdateItem]) {
    super.prepareForCollectionViewUpdates(updateItems)
    
    for item in updateItems {
      switch item.updateAction {
      case .Insert, .Move:
        if let indexPath = item.indexPathAfterUpdate {
          insertCellsToIndexPath(indexPath)
        }
        
      default:
        break
      }
    }
  }
  
  override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
    return !(CGSizeEqualToSize(newBounds.size, collectionView?.frame.size ?? CGSizeZero))
  }
  
  override func invalidateLayout() {
    super.invalidateLayout()
    
    indexPathCache = NSIndexPath(forRow: 0, inSection: 0)
    layoutAttributesCache = [UICollectionViewLayoutAttributes]()
    furthestCellPosition = CGPointZero
    layoutRectCache = CGRectZero
    firstOpenSpace = CGPointZero
    indexPathByPosition = [Int: [Int: NSIndexPath]]()
    positionByIndexPath = [UInt: [UInt: CGPoint]]()
    
  }
}

