master 555aff8d10e3 cached
66 files
352.1 KB
93.3k tokens
2 symbols
1 requests
Download .txt
Showing preview only (375K chars total). Download the full file or copy to clipboard to get everything.
Repository: danylokostyshyn/popcorntime-ios
Branch: master
Commit: 555aff8d10e3
Files: 66
Total size: 352.1 KB

Directory structure:
gitextract_6kv41eo_/

├── .gitignore
├── Podfile
├── PopcornTime/
│   ├── Controllers/
│   │   ├── AnimeDetailsViewController.swift
│   │   ├── AnimeViewController.swift
│   │   ├── BarHidingViewController.swift
│   │   ├── BaseCollectionViewController.swift
│   │   ├── BaseDetailsViewController.swift
│   │   ├── ColorfullTabBarController.swift
│   │   ├── FavoritesViewController.swift
│   │   ├── LoadingViewController.swift
│   │   ├── MovieDetailsViewController.swift
│   │   ├── MoviesViewController.swift
│   │   ├── OAuthViewController.swift
│   │   ├── PagedViewController.swift
│   │   ├── ParseViewController.swift
│   │   ├── SettingsViewController.swift
│   │   ├── ShowDetailsViewController.swift
│   │   └── ShowsViewController.swift
│   ├── Info.plist
│   ├── Models/
│   │   ├── APIManager.swift
│   │   ├── Anime.swift
│   │   ├── AppDelegate.swift
│   │   ├── BaseStructures.swift
│   │   ├── BasicInfo.swift
│   │   ├── DataManager.swift
│   │   ├── Extensions.swift
│   │   ├── Image.swift
│   │   ├── ImageProvider.swift
│   │   ├── Movie.swift
│   │   ├── PTAPIManager.h
│   │   ├── PTAPIManager.m
│   │   ├── PTTorrentStreamer.h
│   │   ├── PTTorrentStreamer.mm
│   │   ├── ParseManager.swift
│   │   └── Show.swift
│   ├── PopcornTime-Bridging-Header.h
│   ├── Resources/
│   │   ├── Images.xcassets/
│   │   │   ├── AnimeIcon.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   ├── BigLogo.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── Contents.json
│   │   │   └── SubwayIconSet/
│   │   │       ├── AddToFavoritesIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       ├── FavoritesIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       ├── MoviesIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       ├── RemoveFromFavoritesIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       ├── SettingsIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       └── ShowsIcon.imageset/
│   │   │           └── Contents.json
│   │   ├── Launch Screen.xib
│   │   └── Main.storyboard
│   └── Views/
│       ├── EpisodeCell.swift
│       ├── EpisodeCell.xib
│       ├── MoreShowsCollectionViewCell.swift
│       ├── MoreShowsCollectionViewCell.xib
│       ├── SeasonHeader.swift
│       ├── SeasonHeader.xib
│       ├── ShowCollectionViewCell.swift
│       ├── ShowCollectionViewCell.xib
│       ├── StratchyHeader.swift
│       ├── StratchyHeader.xib
│       └── StratchyHeaderLayout.swift
├── PopcornTime.xcodeproj/
│   ├── project.pbxproj
│   └── xcshareddata/
│       └── xcschemes/
│           └── PopcornTime.xcscheme
├── README.md
├── Thirdparties/
│   └── VLCKit/
│       └── Dropin-Player/
│           ├── VDLPlaybackViewController.h
│           ├── VDLPlaybackViewController.m
│           └── VDLPlaybackViewController.xib
└── popcorntime_api.paw

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Created by https://www.gitignore.io

### OSX ###
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear on external disk
.Spotlight-V100
.Trashes

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk


### Xcode ###
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.xcuserstate


### Objective-C ###
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
*.xcworkspace/
Pods/

================================================
FILE: Podfile
================================================
# Uncomment this line to define a global platform for your project
# platform :ios, '8.0'
inhibit_all_warnings!

source 'https://github.com/danylokostyshyn/private-podspecs.git'
source 'https://github.com/CocoaPods/Specs'

target 'PopcornTime' do

pod 'private-MobileVLCKit'
pod 'private-boost'
pod 'private-libtorrent'
pod 'private-openssl'
pod 'Reachability'
pod 'CocoaSecurity'
pod 'SDWebImage'

pod 'Crashlytics'
pod 'Fabric'

end


================================================
FILE: PopcornTime/Controllers/AnimeDetailsViewController.swift
================================================
//
//  ShowDetailsViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/13/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class AnimeDetailsViewController: BaseDetailsViewController {
    
    var anime: Anime! {
        get {
            return self.item as! Anime
        }
    }
    // MARK: - UIViewController
    
    override func viewDidLoad() {
        super.viewDidLoad()
        preferedOtherHeadersHeight = 0.0
    }
    
    // MARK: - BaseDetailsViewController
    
    override func reloadData() {
        PTAPIManager.shared().showInfo(with: .anime, withId: item.identifier, success: { (item) -> Void in
            guard let item = item else { return }
            self.anime.update(item)
            self.collectionView?.reloadData()
            }, failure: nil)
    }
    
    // MARK: - DetailViewControllerDataSource
    override func numberOfSeasons() -> Int {
        return anime.seasons.count
    }
    
    override func numberOfEpisodesInSeason(_ seasonsIndex: Int) -> Int {
        return anime.seasons[seasonsIndex].episodes.count
    }
    
    override func setupCell(_ cell: EpisodeCell, seasonIndex: Int, episodeIndex: Int) {
        let episode = anime.seasons[seasonIndex].episodes[episodeIndex]
        cell.titleLabel.text = "\(episode.episodeNumber)"
    }
    
    override func setupSeasonHeader(_ header: SeasonHeader, seasonIndex: Int) {
        
    }
    
    override func cellWasPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int) {
        let episode = anime.seasons[seasonIndex].episodes[episodeIndex]
        showVideoPickerPopupForEpisode(episode, basicInfo: self.item, fromView: cell)
    }
    
    override func cellWasLongPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int) {
//        let episode = anime.episodeFor(seasonIndex: seasonIndex, episodeIndex: episodeIndex)
//        let seasonEpisodes = anime.episodesFor(seasonIndex: seasonIndex)
    }
}


================================================
FILE: PopcornTime/Controllers/AnimeViewController.swift
================================================
//
//  MoviesViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/15/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class AnimeViewController: PagedViewController {

    override var showType: PTItemType {
        get {
            return .anime
        }
    }

    override func map(_ response: [AnyObject]) -> [BasicInfo] {
        return response.map({ Anime(dictionary: $0 as! [AnyHashable: Any]) })
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: IndexPath) {
        
        if let cell = collectionView.cellForItem(at: indexPath){
            //Check if cell is MoreShowsCell
            if let _ = cell as? MoreShowsCollectionViewCell{
                loadMore()
            } else {
                performSegue(withIdentifier: "showDetails", sender: cell)
            }
        }
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)
        
        if segue.identifier == "showDetails"{
            if let episodesVC = segue.destination as? AnimeDetailsViewController{
                if let senderCell = sender as? UICollectionViewCell{
                    if let indexPath = collectionView!.indexPath(for: senderCell){
                        var item: BasicInfo!
                        if (searchController!.isActive) {
                            item = searchResults[indexPath.row]
                        } else {
                            item = items[indexPath.row]
                        }
                        episodesVC.item = item as! Anime
                    }
                }
            }
        }
    }
}


================================================
FILE: PopcornTime/Controllers/BarHidingViewController.swift
================================================
//
//  BarHidingViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/13/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class BarHidingViewController: UIViewController {

    fileprivate var barsVisible:Bool = true {
        willSet {
            self.tabBarController?.tabBar.isHidden = !newValue
            self.navigationController?.navigationBar.isHidden = !newValue
            UIApplication.shared.setStatusBarHidden(!newValue, with: .fade)
        }
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        //Hide bars if needed
        let sizeClass = (horizontal: self.view.traitCollection.horizontalSizeClass, vertical: self.view.traitCollection.verticalSizeClass)
        switch sizeClass{
        case (_,.compact):
            self.barsVisible = false
        default: self.barsVisible = true
        }
    }

}


================================================
FILE: PopcornTime/Controllers/BaseCollectionViewController.swift
================================================
//
//  ShowsCollectionViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/8/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

let reuseIdentifierShow = "ShowCell"
let reuseIdentifierMore = "MoreShowsCell"

///Base class for displaying collection of shows, subclass MUST override reloadData() and set self.shows in it
class BaseCollectionViewController: BarHidingViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate {
    
    fileprivate struct Constants{
        static let desirediPadCellWidth = 160
        static let desirediPadCellHeight = 205
        static let numberOfLinesiPhonePortrait = 2
        static let numberOfItemsiPhonePortrait = 2
        static let numberOfLinesiPhoneLandscape = 2
        static let numberOfItemsiPhoneLandscape = 5
    }
    
    var items = [BasicInfo]()
    var showLoadMoreCell = false
    
    
    @IBOutlet weak var collectionView: UICollectionView!{
        didSet{
            collectionView.alwaysBounceVertical = true
            collectionView.dataSource = self
            collectionView.delegate = self
        }
    }
    @IBOutlet weak var collectionViewLayout: UICollectionViewFlowLayout!
    
    // MARK: UIViewController
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.collectionView!.register(UINib(nibName: "ShowCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: reuseIdentifierShow)
        self.collectionView!.register(UINib(nibName: "MoreShowsCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: reuseIdentifierMore)
        self.collectionView?.delegate = self
        self.collectionView?.collectionViewLayout.invalidateLayout()
        
        self.reloadData()
    }
    
    // MARK: UICollectionViewDataSource
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        let additionalCellsCount = self.showLoadMoreCell ? 1 : 0
        return (items.count + additionalCellsCount)
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        if (self.showLoadMoreCell && indexPath.row == items.count) {
            //Last cell
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierMore, for: indexPath) as! MoreShowsCollectionViewCell
            return cell
        } else {
            //Ordinary show cell
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierShow, for: indexPath) as! ShowCollectionViewCell
            
            let item = items[indexPath.row]
            cell.title = item.title
            
            let imageItem = item.smallImage
            switch imageItem?.status {
            case .new?:
                imageItem?.status = .downloading
                ImageProvider.sharedInstance.imageFromURL(URL: imageItem?.URL) { (downloadedImage) -> () in
                    imageItem?.image = downloadedImage
                    imageItem?.status = .finished
                    
                    collectionView.reloadItems(at: [indexPath])
                }
            case .finished?:
                cell.image = imageItem?.image
            default: break
            }

            return cell
        }
    }

    // MARK: UICollectionViewDelegateFlowLayout & UICollectionViewDelegate
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        let visibleAreaHeight = collectionView.bounds.height - navigationController!.navigationBar.bounds.height - UIApplication.shared.statusBarFrame.height - self.tabBarController!.tabBar.bounds.height
        let visibleAreaWidth = collectionView.bounds.width
        
        //Set cell size based on size class.
        let sizeClass = (horizontal: self.view.traitCollection.horizontalSizeClass, vertical: self.view.traitCollection.verticalSizeClass)
        
        if let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout{
            switch sizeClass{
            case (.compact,.regular):
                //iPhone portrait
                let cellWidth = ((visibleAreaWidth - CGFloat(Constants.numberOfItemsiPhonePortrait - 1)*flowLayout.minimumInteritemSpacing - flowLayout.sectionInset.top - flowLayout.sectionInset.bottom)/CGFloat(Constants.numberOfItemsiPhonePortrait))
                let cellHeight = ((visibleAreaHeight - CGFloat(Constants.numberOfLinesiPhonePortrait - 1)*flowLayout.minimumLineSpacing - flowLayout.sectionInset.left - flowLayout.sectionInset.right)/CGFloat(Constants.numberOfLinesiPhonePortrait))
                return CGSize(width: cellWidth, height: cellHeight)
            case (_,.compact):
                //iPhone landscape
                let cellWidth = ((collectionView.bounds.width - CGFloat(Constants.numberOfItemsiPhoneLandscape - 1)*flowLayout.minimumInteritemSpacing - flowLayout.sectionInset.top - flowLayout.sectionInset.bottom)/CGFloat(Constants.numberOfItemsiPhoneLandscape))
                let cellHeight = ((collectionView.bounds.height - CGFloat(Constants.numberOfLinesiPhoneLandscape - 1)*flowLayout.minimumLineSpacing - flowLayout.sectionInset.left - flowLayout.sectionInset.right)/CGFloat(Constants.numberOfLinesiPhoneLandscape))
                return CGSize(width: cellWidth, height: cellHeight)
            case (_,_):
                // iPad. Calculate cell size based on desired size
                let numberOfLines = Int(visibleAreaHeight) / Constants.desirediPadCellHeight
                let betweenLinesSpaceSum = CGFloat(numberOfLines - 1) * flowLayout.minimumLineSpacing
                let sectionInsetsVerticalSum = flowLayout.sectionInset.top + flowLayout.sectionInset.bottom
                
                let adjustedHeight = (visibleAreaHeight - betweenLinesSpaceSum  - sectionInsetsVerticalSum)/CGFloat(numberOfLines)
                let adjustedWidth = adjustedHeight * CGFloat(Constants.desirediPadCellWidth) / CGFloat(Constants.desirediPadCellHeight)
                
                return CGSize(width: adjustedWidth, height: adjustedHeight)
            }
        }
        
        return CGSize(width: 50, height: 50)
    }
    
    // MARK: - ShowsCollectionViewController
    func reloadData(){
        assert(true, "Sublcass MUST override this method")
    }
}


================================================
FILE: PopcornTime/Controllers/BaseDetailsViewController.swift
================================================
//
//  BaseDetailsViewController.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/21/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

/// With this protocol we encapsulate calls of collectionView indexPathes. For now we have one extra section at the top (empty one with stratchy header), this way if anything changes here we will change all logic here, and all users of this protocol will not have to hcange anything. So it's a good idea to use seasonIndex, episodeIndex instead of indexPathes.
protocol DetailViewControllerDataSource {
    func numberOfSeasons() -> Int
    func numberOfEpisodesInSeason(_ seasonsIndex: Int) -> Int
    func setupCell(_ cell: EpisodeCell, seasonIndex: Int, episodeIndex: Int)
    func setupSeasonHeader(_ header: SeasonHeader, seasonIndex: Int)
    func cellWasPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int)
    func cellWasLongPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int)
}

class BaseDetailsViewController: BarHidingViewController, VDLPlaybackViewControllerDelegate, LoadingViewControllerDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, DetailViewControllerDataSource {
    
    // MARK: - Header related
    let headerMinAspectRatio: CGFloat = 0.4
    let headerWidthToCollectionWidthKoef: CGFloat = 0.3
    var header: StratchyHeader?
    
    var preferedOtherHeadersHeight: CGFloat = 35
    
    var headerSize: CGSize {
        let width = collectionView.bounds.size.width
        let minHeight = width * headerMinAspectRatio
        var height = collectionView.bounds.size.height * headerWidthToCollectionWidthKoef
        height = max(height, minHeight)
        return CGSize(width: width, height: height)
    }
    
    // MARK: -
    let cellReuseIdentifier = "EpisodeCell"
    let firstHeaderReuseIdentifier = "StratchyHeader"
    let otherHeadersReuseIdentifier = "OtherHeader"
    let episodeCellReuseIdentifier = "EpisodeCell"
    
    var layout: StratchyHeaderLayout?

    var item: BasicInfo! {
        didSet {
            navigationItem.title = item.title
            reloadData()
        }
    }

    @IBOutlet weak var collectionView: UICollectionView!{
        didSet{
            collectionView.alwaysBounceVertical = true
            collectionView.dataSource = self
            collectionView.delegate = self
            collectionView.register(UINib(nibName: "StratchyHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: firstHeaderReuseIdentifier)
            collectionView.register(UINib(nibName: "SeasonHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: otherHeadersReuseIdentifier)
            collectionView.register(UINib(nibName: "EpisodeCell", bundle: nil), forCellWithReuseIdentifier: episodeCellReuseIdentifier)
            layout = collectionView.collectionViewLayout as? StratchyHeaderLayout
        }
    }
    
    // MARK: - View Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureFavoriteBarButton()
        
        let longPress = UILongPressGestureRecognizer(target: self, action: #selector(BaseDetailsViewController.longPress(_:)))
        longPress.minimumPressDuration = 0.5
        longPress.delaysTouchesBegan = true
        collectionView.addGestureRecognizer(longPress)
    }
    
    final func longPress(_ gesture: UILongPressGestureRecognizer) {
        if gesture.state == .ended {
            return
        }
        let p = gesture.location(in: collectionView)
        if let indexPath = collectionView.indexPathForItem(at: p) {
            if let cell = collectionView.cellForItem(at: indexPath) {
                cellWasLongPressed(cell, seasonIndex: indexPath.section - 1, episodeIndex: indexPath.item)
            }
        }
    }
    
    func configureFavoriteBarButton() {
        if (item.isFavorite) {
            self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage.removeFromFavoritesImage(),
                style: .done, target: self, action: #selector(BaseDetailsViewController.removeFromFavorites))
        } else {
            self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage.addToFavoritesImage(),
                style: .done, target: self, action: #selector(BaseDetailsViewController.addToFavorites))
        }
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        // update header size
        header?.headerSize = headerSize
        layout?.headerSize = headerSize
    }

    // MARK: - Favorites
    func addToFavorites() {
        DataManager.sharedManager().addToFavorites(item)
        configureFavoriteBarButton()
    }
    
    func removeFromFavorites() {
        DataManager.sharedManager().removeFromFavorites(item)
        configureFavoriteBarButton()
    }
    
    // MARK: - BaseDetailsViewController
    func reloadData() {
        
    }
    
    func startPlayback(_ episode: Episode, basicInfo: BasicInfo, magnetLink: String, loadingTitle: String) {
            
        let loadingVC = self.storyboard?.instantiateViewController(withIdentifier: "loadingViewController") as! LoadingViewController
        loadingVC.delegate = self
        loadingVC.status = "Downloading..."
        loadingVC.loadingTitle = loadingTitle
        loadingVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        self.tabBarController?.present(loadingVC, animated: true, completion: nil)
        
        PTTorrentStreamer.shared().startStreaming(fromFileOrMagnetLink: magnetLink, progress: { (status) -> Void in
            
            loadingVC.progress = status.bufferingProgress
            loadingVC.speed = Int(status.downloadSpeed)
            loadingVC.seeds = Int(status.seeds)
            loadingVC.peers = Int(status.peers)
            
            }, readyToPlay: { (url) -> Void in
                loadingVC.dismiss(animated: false, completion: nil)
                
                let vdl = VDLPlaybackViewController(nibName: "VDLPlaybackViewController", bundle: nil)
                vdl.delegate = self
                self.navigationController?.present(vdl, animated: true, completion: nil)
                vdl.playMedia(from: url)
                
            }, failure: { (error) -> Void in
                loadingVC.dismiss(animated: true, completion: nil)
        })
    }

    // MARK: - VDLPlaybackViewControllerDelegate
    
    func playbackControllerDidFinishPlayback(_ playbackController: VDLPlaybackViewController!) {
        self.navigationController?.dismiss(animated: true, completion: nil)
        PTTorrentStreamer.shared().cancelStreaming()
    }
    
    // MARK: - LoadingViewControllerDelegate
    
    func didCancelLoading(_ controller: LoadingViewController) {
        PTTorrentStreamer.shared().cancelStreaming()
        controller.dismiss(animated: true, completion: nil)
    }
    
    // MARK: - UICollectionViewDataSource
    
    final func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        switch section {
        case 0: return 0
        default:
            let seasonIndex = section - 1
            return self.numberOfEpisodesInSeason(seasonIndex)
        }
    }
    
    final func numberOfSections(in collectionView: UICollectionView) -> Int {
        return self.numberOfSeasons() + 1 // extra section for header
    }
    
    final func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let seasonIndex = indexPath.section - 1
        let episode = indexPath.item
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReuseIdentifier, for: indexPath) as! EpisodeCell
        self.setupCell(cell, seasonIndex: seasonIndex, episodeIndex: episode)
        return cell
    }
    
    final func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        switch section {
        case 0: return headerSize
        default : return CGSize(width: collectionView.bounds.width, height: preferedOtherHeadersHeight)
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        if indexPath.section == 0 {
            if (header == nil){
                header = (collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: firstHeaderReuseIdentifier, for: indexPath) as! StratchyHeader)
                header?.delegate = layout

                if let image = item.bigImage?.image {
                    header?.image = image
                } else {
                    ImageProvider.sharedInstance.imageFromURL(URL: item.bigImage?.URL) { (downloadedImage) -> () in
                        self.item.bigImage?.image = downloadedImage
                        self.header?.image = downloadedImage
                    }
                }
                
                if let image = item.smallImage?.image {
                    header?.foregroundImage.image = image
                } else {
                    ImageProvider.sharedInstance.imageFromURL(URL: item.smallImage?.URL) { (downloadedImage) -> () in
                        self.item.smallImage?.image = downloadedImage
                        self.header?.foregroundImage.image = downloadedImage
                    }
                }
            }
            header!.synopsisTextView.text = item.synopsis
            return header!
        } else {
            let otherHeader = (collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: otherHeadersReuseIdentifier, for: indexPath) as! SeasonHeader)
            let seasonIndex = (indexPath.section - 1)
            self.setupSeasonHeader(otherHeader, seasonIndex: seasonIndex)
            return otherHeader
        }
    }
    
    // MARK: - UICollectionViewDelegate
    
    final func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if let cell = collectionView.cellForItem(at: indexPath) {
            cellWasPressed(cell, seasonIndex: indexPath.section - 1, episodeIndex: indexPath.item)
        }
    }
    
    func showVideoPickerPopupForEpisode(_ episode: Episode, basicInfo: BasicInfo, fromView view: UIView) {
        let videos = episode.videos
        if (videos.count > 0) {
            
            let actionSheetController = UIAlertController(title: episode.title, message: episode.desc, preferredStyle: UIAlertControllerStyle.actionSheet)
            
            let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
            actionSheetController.addAction(cancelAction)
            
            for video in videos {
                var title = ""
                if let subGroup = video.subGroup {
                    title += "[\(subGroup)] "
                }
                if let quality = video.quality {
                    title += quality
                }
                
                let action = UIAlertAction(title: title, style: UIAlertActionStyle.default, handler: { (action) -> Void in
                    let magnetLink = video.magnetLink
                    let episodeTitle = episode.title ?? ""
                    let loadingTitle = "\(episodeTitle) - \(title)"
                    self.startPlayback(episode, basicInfo: basicInfo , magnetLink: magnetLink, loadingTitle: loadingTitle)
                })
                
                actionSheetController.addAction(action)
            }
            
            let popOver = actionSheetController.popoverPresentationController
            popOver?.sourceView  = view
            popOver?.sourceRect = view.bounds
            popOver?.permittedArrowDirections = UIPopoverArrowDirection.any
          
            self.present(actionSheetController, animated: true, completion: nil)
        }
    }
    
    // MARK: - DetailViewControllerDataSource
    func numberOfSeasons() -> Int {
        assertionFailure("Should be overriden by subclass")
        return 0
    }
    
    func numberOfEpisodesInSeason(_ seasonsIndex: Int) -> Int {
        assertionFailure("Should be overriden by subclass")
        return 0
    }
    
    func setupCell(_ cell: EpisodeCell, seasonIndex: Int, episodeIndex: Int) {
        assertionFailure("Should be overriden by subclass")
    }
    
    func setupSeasonHeader(_ header: SeasonHeader, seasonIndex: Int) {
        assertionFailure("Should be overriden by subclass")
    }
    
    func cellWasPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int) {
        assertionFailure("Should be overriden by subclass")
    }
    
    func cellWasLongPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int) {
        
    }
}


================================================
FILE: PopcornTime/Controllers/ColorfullTabBarController.swift
================================================
//
//  ColorfullTabBarController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 4/10/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit


class ColorfullTabBarController: UITabBarController, UITabBarControllerDelegate {
    
    fileprivate struct ColorConstants {
        static let favoritesTintColor = UIColor(red: 235/255, green: 66/255, blue: 69/255, alpha: 1.0)
        static let moviesTintColor = UIColor(red: 66/255, green: 166/255, blue: 235/255, alpha: 1.0)
        static let showsTintColor = UIColor(red: 33/255, green: 181/255, blue: 42/255, alpha: 1.0)
        static let animeTintColor = UIColor(red: 235/255, green: 66/255, blue: 164/255, alpha: 1.0)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.delegate = self
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        assignColors()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        assignColors()
    }
    
    fileprivate func assignColors() {
        switch selectedIndex {
        case 0: view.window?.tintColor = ColorConstants.favoritesTintColor
        case 1: view.window?.tintColor = ColorConstants.moviesTintColor
        case 2: view.window?.tintColor = ColorConstants.showsTintColor
        case 3: view.window?.tintColor = ColorConstants.animeTintColor
        default: break
        }
    }
    
    
    // MARK: - UITabBarControllerDelegate
    
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        self.assignColors()
    }
    
    
}


================================================
FILE: PopcornTime/Controllers/FavoritesViewController.swift
================================================
//
//  FavoritesViewController.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/13/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class FavoritesViewController: PagedViewController {

    override func reloadData() {
        if let favoriteItems = DataManager.sharedManager().favorites {
            self.items = favoriteItems
            self.collectionView?.reloadData()
        }
        
    }
    
    override func loadMore() {

    }
    
    // MARK: View Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // No search in favorites
        self.searchController = nil
        self.navigationItem.titleView = nil

        NotificationCenter.default.addObserver(
            self,
            selector: #selector(FavoritesViewController.favoritesDidChange(_:)),
            name: NSNotification.Name(rawValue: Notifications.FavoritesDidChangeNotification),
            object: nil
        )
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    
    // MARK: - Navigation

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
        if let item = sender as? BasicInfo {
            
            if let episodesVC = segue.destination as? BaseDetailsViewController {
                switch item {
                case item as Anime:
                    episodesVC.item = item as! Anime
                case item as Show:
                    episodesVC.item = item as! Show
                case item as Movie:
                    episodesVC.item = item as! Movie
                default:
                    break
                }
            }
        }
    }
    
    // MARK: - Notifications
    
    func favoritesDidChange(_ notification: Notification) {
        self.reloadData()
    }
    
    // MARK: - UICollectionViewDelegate
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: IndexPath) {
        
        let item = self.items[indexPath.row]
        
        switch item {
        case item as Anime:
            performSegue(withIdentifier: "showDetailsForFavoriteAnime", sender: item)
        case item as Show:
            performSegue(withIdentifier: "showDetailsForFavoriteShow", sender: item)
        case item as Movie:
            performSegue(withIdentifier: "showDetailsForFavoriteMovie", sender: item)
        default:
            break
        }
    }
}


================================================
FILE: PopcornTime/Controllers/LoadingViewController.swift
================================================
//
//  LoadingViewController.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/15/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

protocol LoadingViewControllerDelegate {
    func didCancelLoading(_ controller: LoadingViewController)
}

class LoadingViewController: UIViewController {

    var delegate: LoadingViewControllerDelegate?
    
    @IBOutlet fileprivate weak var statusLabel: UILabel!
    @IBOutlet fileprivate weak var progressLabel: UILabel!
    @IBOutlet fileprivate weak var progressView: UIProgressView!
    @IBOutlet fileprivate weak var speedLabel: UILabel!
    @IBOutlet fileprivate weak var seedsLabel: UILabel!
    @IBOutlet fileprivate weak var peersLabel: UILabel!
    @IBOutlet fileprivate weak var titleLabel: UILabel!
    
    var status: String? = nil {
        didSet {
            if let status = status {
                statusLabel?.text = status
            }
        }
    }
    
    var progress: Float = 0.0 {
        didSet {
            progressView.progress = progress
            progressLabel.text = String(format: "%.0f%%", progress*100)
        }
    }
    
    var speed: Int = 0 { // bytes/s
        didSet {
            let formattedSpeed = ByteCountFormatter.string(fromByteCount: Int64(speed), countStyle: .binary) + "/s"
            speedLabel.text = String(format:"Speed: %@", formattedSpeed)
        }
    }
    
    var seeds: Int = 0 {
        didSet {
            seedsLabel.text = String(format: "Seeds: %d", seeds)
        }
    }
    
    var peers: Int = 0 {
        didSet {
            peersLabel.text = String(format: "Peers: %d", peers)
        }
    }
    
    var loadingTitle: String? = nil {
        didSet {
            if let title = loadingTitle {
                titleLabel?.text = title
            }
        }
    }

    // MARK: - View Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        titleLabel?.text = loadingTitle
        status = "Loading..."
        progress =  0.0
        speed = 0
        seeds = 0
        peers = 0
        
        UIApplication.shared.isIdleTimerDisabled = true;
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidLoad()
        
        UIApplication.shared.isIdleTimerDisabled = false;
    }

    // MARK: - Actions

    @IBAction fileprivate func cancelButtonPressed(_ sender: AnyObject) {
        delegate?.didCancelLoading(self)
    }
    
}


================================================
FILE: PopcornTime/Controllers/MovieDetailsViewController.swift
================================================
//
//  ShowDetailsViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/13/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class MovieDetailsViewController: BaseDetailsViewController {
    
    var movie: Movie! {
        get {
            return self.item as! Movie
        }
    }
    
    // MARK: - UIViewController
    
    override func viewDidLoad() {
        super.viewDidLoad()
        preferedOtherHeadersHeight = 0.0
    }
    
    // MARK: - BaseDetailsViewController
    
    override func reloadData() {
        PTAPIManager.shared().showInfo(with: .movie, withId: item.identifier, success: { (item) -> Void in
            guard let item = item else { return }
            self.movie.update(item)
            self.collectionView?.reloadData()
            }, failure: nil)
    }
    
    // MARK: - DetailViewControllerDataSource
    override func numberOfSeasons() -> Int {
        return 1
    }
    
    override func numberOfEpisodesInSeason(_ seasonsIndex: Int) -> Int {
        return movie.videos.count
    }
    
    override func setupCell(_ cell: EpisodeCell, seasonIndex: Int, episodeIndex: Int) {
        let video = movie.videos[episodeIndex]
        var title = ""
        if let quality = video.quality {
            title += quality + " "
        }
        if let name = video.name {
            title += name
        }
        cell.titleLabel.text = title
    }
    
    override func setupSeasonHeader(_ header: SeasonHeader, seasonIndex: Int) {
    }
    
    override func cellWasPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int) {
        let video = movie.videos[episodeIndex]
        let magnetLink = video.magnetLink
        let title = movie.title ?? ""
        let fakeEpisode = Episode(title: title, desc: "", seasonNumber: 0, episodeNumber: 0, videos: [Video]())
        startPlayback(fakeEpisode, basicInfo: movie, magnetLink: magnetLink, loadingTitle: title)
    }
    
}


================================================
FILE: PopcornTime/Controllers/MoviesViewController.swift
================================================
//
//  MoviesViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/19/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class MoviesViewController: PagedViewController {
    
    override var showType: PTItemType {
        get {
            return .movie
        }
    }

    override func map(_ response: [AnyObject]) -> [BasicInfo] {
        let items = response.map({ Movie(dictionary: $0 as! [AnyHashable: Any]) }) as [BasicInfo]
        return items
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: IndexPath) {
        
        if let cell = collectionView.cellForItem(at: indexPath){
            //Check if cell is MoreShowsCell
            if let _ = cell as? MoreShowsCollectionViewCell{
                loadMore()
            } else {
                performSegue(withIdentifier: "showDetails", sender: cell)
            }
        }
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)
        
        if segue.identifier == "showDetails"{
            if let episodesVC = segue.destination as? MovieDetailsViewController{
                if let senderCell = sender as? UICollectionViewCell{
                    if let indexPath = collectionView!.indexPath(for: senderCell) {
                        var item: BasicInfo!
                        if (searchController!.isActive) {
                            item = searchResults[indexPath.row]
                        } else {
                            item = items[indexPath.row]
                        }
                        episodesVC.item = item as! Movie
                    }
                }
            }
        }
    }
}


================================================
FILE: PopcornTime/Controllers/OAuthViewController.swift
================================================
//
//  WebViewController.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/15/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

protocol OAuthViewControllerDelegate {
    func oauthViewControllerDidFinish(_ controller: OAuthViewController, token: String?, error: NSError?)
}

class OAuthViewController: UIViewController, UIWebViewDelegate {

    @IBOutlet weak var webView: UIWebView!
    @IBOutlet weak var navigationBar: UINavigationBar!
    var delegate: OAuthViewControllerDelegate?
    var URL: Foundation.URL?
    
    // MARK: - View Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()

        if let URL = URL {
            webView.loadRequest(URLRequest(url: URL))
        }
    }
    
    // MARK: - UIWebViewDelegate
    
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        if let code = request.url?.lastPathComponent {
            if code.characters.count == 64 {
//                PTAPIManager.sharedManager().accessTokenWithAuthorizationCode(code, success: { (accessToken) -> Void in
//                    println("OAuth access token: \(accessToken)")
//                    self.delegate?.oauthViewControllerDidFinish(self, token: accessToken, error: nil)
//                }, failure: { (error) -> Void in
//                    println("\(error)")
//                    self.delegate?.oauthViewControllerDidFinish(self, token: nil, error: error)
//                })
            }
        }
        return true;
    }
    
    func webViewDidStartLoad(_ webView: UIWebView) {
        
    }
    
    func webViewDidFinishLoad(_ webView: UIWebView) {

    }
    
    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
        delegate?.oauthViewControllerDidFinish(self, token: nil, error: error as NSError?)
    }
    
    // MARK: - Actions
    
    @IBAction func cancelButtonPressed(_ sender: AnyObject) {
        delegate?.oauthViewControllerDidFinish(self, token: nil, error: nil)
    }
    
}


================================================
FILE: PopcornTime/Controllers/PagedViewController.swift
================================================
//
//  PagedViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/19/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class PagedViewController: BaseCollectionViewController, UISearchBarDelegate, UISearchResultsUpdating  {
   
    fileprivate var contentPage: UInt = 0

    var searchResults = [BasicInfo]()
    var searchController: UISearchController?
    var searchTimer: Timer?

    var showType: PTItemType {
        get {
            assert(false, "this must be overriden by subclass")
            return .movie
        }
    }
    
    // MARK: View Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupSearch()
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        
        collectionViewLayout?.invalidateLayout()
    }
    
    fileprivate func setupSearch() {
        
        self.definesPresentationContext = true
        
        searchController = UISearchController(searchResultsController: nil)
        searchController!.searchResultsUpdater = self
        searchController!.hidesNavigationBarDuringPresentation = false
        searchController!.dimsBackgroundDuringPresentation = false
        
        let searchBar = searchController!.searchBar
        searchBar.delegate = self
        searchBar.barStyle = .black
        searchBar.backgroundImage = UIImage()
        
        
        let searchBarContainer = UIView(frame: navigationController!.navigationBar.bounds)
        searchBarContainer.addSubview(searchBar)
        searchBar.translatesAutoresizingMaskIntoConstraints = false
        navigationItem.titleView = searchBarContainer
        
        let views = ["searchBar" : searchBar]
        searchBarContainer.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[searchBar]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
        searchBarContainer.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[searchBar]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
    }

    // MARK:
    
    func map(_ response: [AnyObject]) -> [BasicInfo] {
        return [BasicInfo]()
    }
    
    override func reloadData() {
        PTAPIManager.shared().topShows(with: showType, withPage: contentPage, success: { (items) -> Void in
            self.showLoadMoreCell = true
            if let items = items {
                self.items = self.map(items as [AnyObject])
                self.collectionView?.reloadData()
            }
            }, failure: nil)
    }
    
    func loadMore() {
        PTAPIManager.shared().topShows(with: showType, withPage: contentPage+1, success: { (items) -> Void in
            if let items = items {
                self.contentPage += 1
                let newItems = self.map(items as [AnyObject])
                let newShowsIndexPathes = newItems.enumerated().map({ (index, item) in
                    return IndexPath(row: (self.items.count + index), section: 0)
                })
                self.items += newItems
                
                self.collectionView?.insertItems(at: newShowsIndexPathes)
            }
            }, failure: nil)
    }
    
    func performSearch() {
        let text = searchController!.searchBar.text
        if text!.characters.count > 0 {
            PTAPIManager.shared().searchForShow(with: showType, name: text, success: { (items) -> Void in
                self.showLoadMoreCell = false
                if let items = items {
                    self.searchResults = self.map(items as [AnyObject])
                } else {
                    self.searchResults.removeAll(keepingCapacity: false)
                }
                self.collectionView?.reloadData()
                }, failure: nil)
        }
    }

    // MARK: UICollectionViewDataSource
    
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if searchController != nil && searchController!.isActive {
            return searchResults.count
        }
        return super.collectionView(collectionView, numberOfItemsInSection: section)
    }
    
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if searchController != nil && searchController!.isActive {
            //Ordinary show cell
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierShow, for: indexPath) as! ShowCollectionViewCell
            
            let item = searchResults[indexPath.row]
            cell.title = item.title

            let imageItem = item.smallImage
            switch imageItem?.status {
            case .new?:
                imageItem?.status = .downloading
                ImageProvider.sharedInstance.imageFromURL(URL: imageItem?.URL) { (downloadedImage) -> () in
                    imageItem?.image = downloadedImage
                    imageItem?.status = .finished
                    
                    collectionView.reloadItems(at: [indexPath])
                }
            case .finished?:
                cell.image = imageItem?.image
            default: break
            }

            return cell
        }
        return super.collectionView(collectionView, cellForItemAt: indexPath)
    }
    
    // MARK: UICollectionViewDelegate
    
    func collectionView(_ collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: IndexPath) {
        if indexPath.row == items.count {
            loadMore()
        }
    }
    
    // MARK: UISearchBarDelegate
    
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        self.searchTimer?.invalidate()
        self.searchTimer = nil
        performSearch()
    }
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        
        self.showLoadMoreCell = true
        
        self.searchTimer?.invalidate()
        self.searchTimer = nil
        
        searchResults.removeAll(keepingCapacity: false)
        self.collectionView.reloadData()
    }
    
    // MARK: UISearchResultsUpdating
    
    func updateSearchResults(for searchController: UISearchController) {
        self.searchTimer?.invalidate()
        self.collectionView.reloadData()
        self.searchTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(PagedViewController.performSearch), userInfo: nil, repeats: false)
    }
}


================================================
FILE: PopcornTime/Controllers/ParseViewController.swift
================================================
//
//  ParseViewController.swift
//
//
//  Created by Andriy K. on 6/22/15.
//
//

import UIKit

class ParseViewController: UIViewController, PFLogInViewControllerDelegate {
    
    private var canPromptLogin = true
    
    // MARK: - UIViewController
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        promptLoginIfNeeded(true)
    }
    
    // MARK: - Login
    
    func promptLoginIfNeeded(animated: Bool) {
        
        let currentUser = ParseManager.sharedInstance.user
        if currentUser == nil {
            // Show the signup or login screen
            let logInController = PFLogInViewController()
            logInController.delegate = self
            logInController.fields =
                [PFLogInFields.DismissButton, PFLogInFields.Facebook]
            logInController.facebookPermissions = ["public_profile"]
            self.presentViewController(logInController, animated:animated, completion: nil)
        }
    }
    
    // MARK: PFLogInViewControllerDelegate
    
    func logInViewController(logInController: PFLogInViewController, didLogInUser user: PFUser) {
        dissmiss(nil)
    }
    
    func logInViewController(logInController: PFLogInViewController, didFailToLogInWithError error: NSError?) {
    }
    
    func logInViewControllerDidCancelLogIn(logInController: PFLogInViewController) {
        dissmiss(nil)
        dissmiss(nil)
    }
    
    // MARK: - Actions
    
    @IBAction func dissmiss(sender: AnyObject?) {
        canPromptLogin = false
        self.dismissViewControllerAnimated(true, completion: nil)
    }
    
    @IBAction func logOutPressed(sender: UIBarButtonItem) {
        PFUser.logOut()
        dissmiss(nil)
    }
    @IBAction func clearAllDataPressed(sender: UIBarButtonItem) {
    }
    
}


================================================
FILE: PopcornTime/Controllers/SettingsViewController.swift
================================================
//
//  SettingsViewController.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 4/4/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class SettingsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    // MARK: - View Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    // MARK: - 
    
    func appInfoString() -> String {
        let displayName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as! String
        let version = Bundle.main.infoDictionary?["CFBundleVersion"] as! String
        let shortVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String
        return "\(displayName) \(shortVersion) (\(version))"
    }
    
    // MARK: - UITableViewDataSource
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let identifier = "SettingsCell"
        var cell: UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: "SettingsCell") 
        if cell == nil {
            cell = UITableViewCell(style: .default, reuseIdentifier: identifier)
        }

        cell.textLabel?.text = "Hello, PopcornTime!"
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        let label = UILabel(frame: CGRect(x: 0.0, y: 0.0, width: tableView.bounds.width, height: 0.0))
        label.backgroundColor = UIColor.clear
        label.font = UIFont.systemFont(ofSize: 14.0)
        label.text = appInfoString()
        label.textAlignment = .center
        return label
    }
    
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 30.0
    }
    
    // MARK: - UITableViewDelegate
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView .deselectRow(at: indexPath, animated: true)
    }
    
    @IBAction func doneButtonTapped(_ sender: AnyObject) {
        self.dismiss(animated: true, completion: nil)
    }
}


================================================
FILE: PopcornTime/Controllers/ShowDetailsViewController.swift
================================================
//
//  ShowDetailsViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/13/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class ShowDetailsViewController: BaseDetailsViewController {
    
    var show: Show! {
        get {
            return self.item as! Show
        }
    }
    
    // MARK: - BaseDetailsViewController
    
    override func reloadData() {
        PTAPIManager.shared().showInfo(with: .show, withId: show.identifier, success: { (item) -> Void in
            guard let item = item else { return }
            self.show.update(item)
            self.collectionView?.reloadData()
            }, failure: nil)
    }
    
    // MARK: - DetailViewControllerDataSource
    override func numberOfSeasons() -> Int {
        return show.seasons.count
    }
    
    override func numberOfEpisodesInSeason(_ seasonsIndex: Int) -> Int {
        return show.seasons[seasonsIndex].episodes.count
    }
    
    override func setupCell(_ cell: EpisodeCell, seasonIndex: Int, episodeIndex: Int) {
        let episode = show.seasons[seasonIndex].episodes[episodeIndex]
        if let title = episode.title {
            cell.titleLabel.text = "S\(episode.seasonNumber)E\(episode.episodeNumber):  \(title)"
        } else {
            cell.titleLabel.text = "S\(episode.seasonNumber)E\(episode.episodeNumber)"
        }
    }
    
    override func setupSeasonHeader(_ header: SeasonHeader, seasonIndex: Int) {
        let seasonNumber = self.show.seasons[seasonIndex].seasonNumber
        header.titleLabel.text = "Season \(seasonNumber)"
    }
    
    override func cellWasPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int) {
        let episode = show.episodeFor(seasonIndex: seasonIndex, episodeIndex: episodeIndex)
        showVideoPickerPopupForEpisode(episode, basicInfo: self.item, fromView: cell)
    }
    
    override func cellWasLongPressed(_ cell: UICollectionViewCell, seasonIndex: Int, episodeIndex: Int) {
//        let episode = show.episodeFor(seasonIndex: seasonIndex, episodeIndex: episodeIndex)
//        let seasonEpisodes = show.episodesFor(seasonIndex: seasonIndex)
    }
}


================================================
FILE: PopcornTime/Controllers/ShowsViewController.swift
================================================
//
//  TVSeriesShowsViewController.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/9/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class ShowsViewController: PagedViewController {
    
    override var showType: PTItemType {
        get {
            return .show
        }
    }
    
    override func map(_ response: [AnyObject]) -> [BasicInfo] {
        return response.map({ Show(dictionary: $0 as! [AnyHashable: Any]) })
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: IndexPath) {
        
        if let cell = collectionView.cellForItem(at: indexPath){
            //Check if cell is MoreShowsCell
            if let _ = cell as? MoreShowsCollectionViewCell {
                loadMore()
            } else {
                performSegue(withIdentifier: "showDetails", sender: cell)
            }
        }
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)
        
        if segue.identifier == "showDetails" {
            if let episodesVC = segue.destination as? ShowDetailsViewController {
                if let senderCell = sender as? UICollectionViewCell {
                    if let indexPath = collectionView!.indexPath(for: senderCell) {
                        var item: BasicInfo!
                        if (searchController!.isActive) {
                            item = searchResults[indexPath.row]
                        } else {
                            item = items[indexPath.row]
                        }
                        episodesVC.item = item as! Show
                    }
                }
            }
        }
    }
}


================================================
FILE: PopcornTime/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleDisplayName</key>
	<string>Popcorn Time</string>
	<key>CFBundleExecutable</key>
	<string>${EXECUTABLE_NAME}</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>${PRODUCT_NAME}</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1.0</string>
	<key>Fabric</key>
	<dict>
		<key>APIKey</key>
		<string>API_KEY</string>
		<key>Kits</key>
		<array>
			<dict>
				<key>KitInfo</key>
				<dict/>
				<key>KitName</key>
				<string>Crashlytics</string>
			</dict>
		</array>
	</dict>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSAllowsArbitraryLoads</key>
		<true/>
	</dict>
	<key>UILaunchStoryboardName</key>
	<string>Launch Screen</string>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array/>
	<key>UIStatusBarHidden</key>
	<true/>
	<key>UIStatusBarStyle</key>
	<string>UIStatusBarStyleBlackOpaque</string>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UIViewControllerBasedStatusBarAppearance</key>
	<false/>
</dict>
</plist>


================================================
FILE: PopcornTime/Models/APIManager.swift
================================================
//
//  APIManager.swift
//  popcornTime
//
//  Created by Danylo Kostyshyn on 3/13/15.
//  Copyright (c) 2015 Danylo Kostyshyn. All rights reserved.
//

/*
http://ytspt.re/api/list.json?limit=30&order=desc&sort=seeds
http://ytspt.re/api/listimdb.json?imdb_id=tt2245084
http://ytspt.re/api/list.json?limit=30&keywords=terminator&order=desc&sort=seeds&set=1
http://www.yifysubtitles.com//subtitle-api/big-hero-6-yify-36523.zip

http://eztvapi.re/shows/1?limit=30&order=desc&sort=seeds
http://eztvapi.re/show/tt0898266
http://eztvapi.re/shows/1?limit=30&keywords=the+big+bang&order=desc&sort=seeds

http://ptp.haruhichan.com/list.php?
http://ptp.haruhichan.com/anime.php?id=912
*/

import Foundation

class APIManager {

    typealias APIManagerFailure = (error: NSError?) -> ()
    typealias APIManagerSuccessItems = (items: [AnyObject]?) -> ()
    typealias APIManagerSuccessItem = (item: [String: AnyObject]?) -> ()
    
    private let APIManagerMoviesEndPoint = "http://ytspt.re/api"
    private let APIManagerShowsEndPoint = "http://eztvapi.re"
    private let APIManagerResultsLimit = 30
    
    class func sharedManager() -> APIManager {
        struct Static { static let instance: APIManager = APIManager() }
        return Static.instance
    }
    
    private func data(url: NSURL, sucess: ((AnyObject?) -> ())?, failure: APIManagerFailure?) {
        NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: {
            (data, response, error) -> Void in
            
            var serializationError: NSError?
            var JSONObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &serializationError)

            if let serializationError = serializationError {
                println("\(serializationError)")
                
                if let failure = failure {
                    failure(error: serializationError)
                }
            }
            
            if let sucess = sucess {
                sucess(JSONObject)
            }
            
        }).resume()
    }
    
    // MARK: Movies
    
    func topMovies(success: APIManagerSuccessItems?, failure: APIManagerFailure?) {
        var path = String(format: "list.json?limit=%d&order=desc&sort=seeds", APIManagerResultsLimit)
        var url = NSURL(string: APIManagerMoviesEndPoint.stringByAppendingPathComponent(path))
        
        data(url!, sucess: { (JSONObject) -> () in
            if let success = success {
                var dict = JSONObject as [String: AnyObject]
                success(items: dict["MovieList"] as [AnyObject]?)
            }
        }, failure: failure)
    }
    
    func movieInfo(imdbId: String, success: APIManagerSuccessItems?, failure: APIManagerFailure?) {
        var path = String(format: "listimdb.json?imdb_id=%@", imdbId)
        var url = NSURL(string: APIManagerMoviesEndPoint.stringByAppendingPathComponent(path))
        
        data(url!, sucess: { (JSONObject) -> () in
            if let success = success {
                var dict = JSONObject as [String: AnyObject]
                success(items: dict["MovieList"] as [AnyObject]?)
            }
        }, failure: failure)
    }
    
    func searchMovie(name: String, success: APIManagerSuccessItems?, failure: APIManagerFailure?) {
        var path = String(format: "list.json?limit=%lu&keywords=%@&order=desc&sort=seeds&set=1", APIManagerResultsLimit, name)
        var url = NSURL(string: APIManagerMoviesEndPoint.stringByAppendingPathComponent(path))
        
        data(url!, sucess: { (JSONObject) -> () in
            if let success = success {
                var dict = JSONObject as [String: AnyObject]
                success(items: dict["MovieList"] as [AnyObject]?)
            }
        }, failure: failure)
    }
    
    // MARK: Shows    
    
    func topShows(page: UInt, success: APIManagerSuccessItems?, failure: APIManagerFailure?) {
        var path = String(format: "shows/%lu?limit=%lu&order=desc&sort=seeds", (page + 1), APIManagerResultsLimit)
        var url = NSURL(string: APIManagerShowsEndPoint.stringByAppendingPathComponent(path))
        
        data(url!, sucess: { (JSONObject) -> () in
            if let success = success {
                success(items: JSONObject as [AnyObject]?)
            }
        }, failure: failure)
    }
    
    func showInfo(imdbId: String, success: APIManagerSuccessItem?, failure: APIManagerFailure?) {
        var path = String(format: "show/%@", imdbId)
        var url = NSURL(string: APIManagerShowsEndPoint.stringByAppendingPathComponent(path))
        
        data(url!, sucess: { (JSONObject) -> () in
            if let success = success {
                success(item: JSONObject as [String: AnyObject]?)
            }
        }, failure: failure)
    }
    
    func searchShow(name: String, success: APIManagerSuccessItems?, failure: APIManagerFailure?) {
        var path = String(format: "shows/1?limit=%lu&keywords=%@&sort=seeds", APIManagerResultsLimit, name)
        var url = NSURL(string: APIManagerShowsEndPoint.stringByAppendingPathComponent(path))
        
        data(url!, sucess: { (JSONObject) -> () in
            if let success = success {
                success(items: JSONObject as [AnyObject]?)
            }
        }, failure: failure)
    }
    
}

================================================
FILE: PopcornTime/Models/Anime.swift
================================================
//
//  Anime.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/19/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import Foundation

class Anime: BasicInfo {
    var seasons = [Season]()

    required init(dictionary: [AnyHashable: Any]) {
        super.init(dictionary: dictionary)
        
        let id = dictionary["id"] as! Int
        identifier = "\(id)"
        title = dictionary["name"] as? String
        year = dictionary["name"] as? String

        if let poster = dictionary["malimg"] as? String {
            images = [Image]()
            
            let URL = Foundation.URL(string: poster)
            let image = Image(URL: URL!, type: .poster)
            images.append(image)
        }
        
        smallImage = images.filter({$0.type == ImageType.poster}).first
        bigImage = smallImage
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }
    
    override func update(_ dictionary: [AnyHashable: Any]) {
        seasons.removeAll(keepingCapacity: true)
        
        let episodesDicts = dictionary["episodes"] as! [[AnyHashable: Any]]
        let seasonNumber:UInt = 0
        
        var videosContainer = [Int: [Video]]()
        var episodesContainer = [Int: Episode]()
        synopsis = dictionary["synopsis"] as? String
        if let sps = synopsis {
            synopsis = sps.replacingOccurrences(of: "oatRightHeader\">EditSynopsis\n", with: "")
        }

        
        for episodeDict in episodesDicts{
            let title = episodeDict["name"] as! String
            let numbersFromTitle = numbersFromAnimeTitle(title)
            let synopsis = episodeDict["overview"] as? String
            if numbersFromTitle.count > 0 {
                if let quality = episodeDict["quality"] as? String{
                    // Get entry data
                    let subGroup = episodeDict["subgroup"] as? String
                    let episodeNumber = numbersFromTitle.first!
                    let magnetLink = episodeDict["magnet"] as! String
                    let video = Video(name: title, quality: quality, size: 0, duration: 0, subGroup: subGroup, magnetLink: magnetLink)
                    
                    var videos = videosContainer[episodeNumber]
                    if (videos == nil) {
                        videos = [Video]()
                        videosContainer[episodeNumber] = videos
                    }
                    videosContainer[episodeNumber]!.append(video)
                    
                    
                    var episode = episodesContainer[episodeNumber]
                    if (episode == nil) {
                        episode = Episode(title: title, desc: synopsis, seasonNumber: seasonNumber, episodeNumber: UInt(episodeNumber), videos: [Video]())
                        episodesContainer[episodeNumber] = episode!
                    }
                }
            }
        }
        
        for entry in videosContainer {
            let episodeNumber = entry.0
            let videos = entry.1
            
            episodesContainer[episodeNumber]!.videos = videos
        }
        
        
        let episodes = Array(episodesContainer.values).sorted { (a, b) -> Bool in
            return a.episodeNumber > b.episodeNumber
        }
        
        let season = Season(seasonNumber: seasonNumber, episodes: episodes)
        seasons.append(season)
    }
    
    fileprivate func numbersFromAnimeTitle(_ title: String) -> [Int]{
        let components = title.components(separatedBy: CharacterSet(charactersIn: "[]_() "))
        var numbers = [Int]()
        for component in components {
            if let number = Int(component) {
                if number < 10000 {
                    numbers.append(number)
                }
            }
        }
        return numbers
    }
}

extension Anime: ContainsEpisodes {
    func episodeFor(seasonIndex: Int, episodeIndex: Int) -> Episode {
        let episode = seasons[seasonIndex].episodes[episodeIndex]
        return episode
    }
    
    func episodesFor(seasonIndex: Int) -> [Episode] {
        return seasons[seasonIndex].episodes
    }
}


================================================
FILE: PopcornTime/Models/AppDelegate.swift
================================================
//
//  AppDelegate.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/13/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

#if RELEASE
import Fabric
import Crashlytics
#endif

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
#if RELEASE
        Fabric.with([Crashlytics()])
#endif
        return true
    }
    
}


================================================
FILE: PopcornTime/Models/BaseStructures.swift
================================================
//
//  Video.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/21/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

struct Video {
    let name: String?
    let quality: String?
    let size: UInt?
    let duration: UInt?
    let subGroup: String?
    let magnetLink: String
}

struct Episode {
    let title: String?
    let desc: String?
    let seasonNumber: UInt
    let episodeNumber: UInt
    var videos = [Video]()
}

struct Season {
    let seasonNumber: UInt
    let episodes: [Episode]
}


================================================
FILE: PopcornTime/Models/BasicInfo.swift
================================================
//
//  BasicInfo.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/19/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import Foundation

protocol ContainsEpisodes {
    func episodeFor(seasonIndex: Int, episodeIndex: Int) -> Episode
    func episodesFor(seasonIndex: Int) -> [Episode]
}

protocol BasicInfoProtocol {
    var identifier: String! {get}
    var title: String? {get}
    var year: String? {get}
    var images: [Image]! {get}
    var smallImage: Image? {get}
    var bigImage: Image? {get}
    var isFavorite: Bool {get}
 
    init(dictionary: [AnyHashable: Any])
    func update(_ dictionary: [AnyHashable: Any])
}

class BasicInfo: NSObject, BasicInfoProtocol, NSCoding {
    var identifier: String!
    var title: String?
    var year: String?
    var images: [Image]!
    var smallImage: Image?
    var bigImage: Image?
    var synopsis: String?

    var isFavorite : Bool {
        get {
            return DataManager.sharedManager().isFavorite(self)
        }
        set {
            if (isFavorite == true) {
                return DataManager.sharedManager().addToFavorites(self)
            } else {
                return DataManager.sharedManager().removeFromFavorites(self)
            }
        }
    }
    
    required init(dictionary: [AnyHashable: Any]) {
//        fatalError("init(dictionary:) has not been implemented")
    }

    func update(_ dictionary: [AnyHashable: Any]) {
        fatalError("update(dictionary:) has not been implemented")
    }
    
    // MARK: - NSCoding
    
    required init?(coder aDecoder: NSCoder) {
        guard
            let identifier = aDecoder.decodeObject(forKey: "identifier") as? String
            else { return nil }
        
        self.identifier = identifier
        self.title = aDecoder.decodeObject(forKey: "title") as? String
        self.year = aDecoder.decodeObject(forKey: "year") as? String
        self.smallImage = aDecoder.decodeObject(forKey: "smallImage") as? Image
        self.bigImage = aDecoder.decodeObject(forKey: "bigImage") as? Image
    }
    
    func encode(with aCoder: NSCoder) {
        aCoder.encode(identifier, forKey: "identifier")
        aCoder.encode(title, forKey: "title")
        aCoder.encode(year, forKey: "year")
        aCoder.encode(smallImage, forKey: "smallImage")
        aCoder.encode(bigImage, forKey: "bigImage")
    }
}


================================================
FILE: PopcornTime/Models/DataManager.swift
================================================
//
//  DataManager.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/24/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import Foundation

struct Notifications {
    static let FavoritesDidChangeNotification = "FavoritesDidChangeNotification"
}

class DataManager {
    let documentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as String
    let fileName = "Favorites.plist"
    var filePath: String {
        get {
            return fileURL.path
        }
    }
    var fileURL: URL {
        let url = URL(fileURLWithPath: documentsDirectory, isDirectory: true)
        return url.appendingPathComponent(fileName)
    }
    var favorites: [BasicInfo]?

    init() {
        loadFavorites()
    }
    
    class func sharedManager() -> DataManager {
        struct Static { static let instance: DataManager = DataManager() }
        return Static.instance
    }

    fileprivate func loadFavorites() -> [BasicInfo]? {
        if FileManager.default.fileExists(atPath: filePath) {
            let data = try? Data(contentsOf: URL(fileURLWithPath: filePath))
            if let data = data {
                self.favorites = NSKeyedUnarchiver.unarchiveObject(with: data) as! [BasicInfo]?
                return self.favorites
            }
        }
        return nil
    }
    
    fileprivate func saveFavorites(_ items: [BasicInfo]) {
        let data = NSKeyedArchiver.archivedData(withRootObject: items)
        try? data.write(to: URL(fileURLWithPath: filePath), options: [.atomic])
        self.favorites = items
    }
    
    // MARK: -
    
    func isFavorite(_ item: BasicInfo) -> Bool {
        let favoriteItem = self.favorites?.filter({ $0.identifier == item.identifier }).first
        if favoriteItem != nil {
            return true
        }
        return false
    }
    
    func addToFavorites(_ item: BasicInfo) {
        var items = [BasicInfo]()
        if let favorites = loadFavorites() {
            items += favorites
        }
        items.append(item)
        saveFavorites(items)
        
        NotificationCenter.default.post(name: Notification.Name(rawValue: Notifications.FavoritesDidChangeNotification), object: nil)
    }
    
    func removeFromFavorites(_ item: BasicInfo) {
        let items = loadFavorites()
            if var items = items {
            let favoriteItem = items.filter({ $0.identifier == item.identifier }).first
            if let favoriteItem = favoriteItem {
                let idx = items.index(of: favoriteItem)
                items.remove(at: idx!)
                saveFavorites(items)

                NotificationCenter.default.post(name: Notification.Name(rawValue: Notifications.FavoritesDidChangeNotification), object: nil)
            }
        }
    }
}

    


================================================
FILE: PopcornTime/Models/Extensions.swift
================================================
//
//  UIImage+PopcornTime.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/30/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

extension UIImage {
    
    class func addToFavoritesImage() -> UIImage? {
        return UIImage(named: "AddToFavoritesIcon")
    }
    
    class func removeFromFavoritesImage() -> UIImage? {
        return UIImage(named: "RemoveFromFavoritesIcon")
    }
    
}


================================================
FILE: PopcornTime/Models/Image.swift
================================================
//
//  File.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/21/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

enum ImageType: Int {
    case banner, poster, fanart
}

enum ImageStatus {
    case new, downloading, finished
}

class Image: NSObject, NSCoding {
    let URL: Foundation.URL
    var image: UIImage?
    let type: ImageType
    var status: ImageStatus = .new
    
    init(URL: Foundation.URL, type: ImageType) {
        self.URL = URL
        self.type = type
    }
    
    // MARK: - NSCoding
    
    required init?(coder aDecoder: NSCoder) {
        let typeRaw = aDecoder.decodeInteger(forKey: "type")
        guard
            let URL = aDecoder.decodeObject(forKey: "URL") as? Foundation.URL,
            let type = ImageType(rawValue: typeRaw)
            else { return nil }
        
        self.URL = URL
        self.type = type
    }
    
    func encode(with aCoder: NSCoder) {
        aCoder.encode(URL, forKey: "URL")
        aCoder.encode(type.rawValue, forKey: "type")
    }
}


================================================
FILE: PopcornTime/Models/ImageProvider.swift
================================================
//
//  ImageProvider.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/10/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class ImageProvider: NSObject {
    
    static let sharedInstance = ImageProvider()

    func imageFromURL(URL: Foundation.URL?, completionBlock: @escaping (_ downloadedImage: UIImage?)->()) {
        guard let URL = URL else { return }
        
        SDWebImageDownloader.shared().downloadImage(with: URL, options: [SDWebImageDownloaderOptions.useNSURLCache], progress: nil) {
            (image, data, error, finished) -> Void in
            if let _ = error { NSLog("\(#function): \(error)") }

            DispatchQueue.main.async(execute: {
                completionBlock(image)
            })
        }
    }
    
}


================================================
FILE: PopcornTime/Models/Movie.swift
================================================
//
//  Movie.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/19/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import Foundation

class Movie: BasicInfo {
    var videos = [Video]()

    required init(dictionary: [AnyHashable: Any]) {
        super.init(dictionary: dictionary)

        let id = (dictionary["id"] as! NSString).intValue
        identifier = "\(id)"
        title = dictionary["title"] as? String
        year = String(describing: dictionary["year"])
        
        images = [Image]()
        if let cover = dictionary["poster_med"] as? String {
            let image = Image(URL: URL(string: cover)!, type: .poster)
            images.append(image)
        }
        
        if let cover = dictionary["poster_big"] as? String {
            let image = Image(URL: URL(string: cover)!, type: .banner)
            images.append(image)
        }

        smallImage = self.images.filter({$0.type == ImageType.poster}).first
        bigImage = self.images.filter({$0.type == ImageType.banner}).first
        synopsis = dictionary["description"] as? String
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }
    
    override func update(_ dictionary: [AnyHashable: Any]) {
        videos.removeAll(keepingCapacity: true)
        
        let title = dictionary["title"] as! String
        
        guard let movieList = dictionary["items"] as? [[AnyHashable: Any]] else { return }
        for movieDict in movieList {
            let quality = movieDict["quality"] as! String
            let magnetLink = movieDict["torrent_magnet"] as! String
            let size = movieDict["size_bytes"] as! UInt

            let video = Video(name: title, quality: quality, size: size, duration: 0, subGroup: nil, magnetLink: magnetLink)
            videos.append(video)
        }
    }
}


================================================
FILE: PopcornTime/Models/PTAPIManager.h
================================================
//
//  PTAPIManager.h
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 2/25/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef void (^PTAPIManagerFailure)(NSError *error);
typedef void (^PTAPIManagerSuccessItems)(NSArray *items);
typedef void (^PTAPIManagerSuccessItem)(NSDictionary *item);
typedef void (^PTAPIManagerSuccessNone)();

typedef NS_ENUM(NSInteger, PTItemType) {
    PTItemTypeMovie,
    PTItemTypeShow,
    PTItemTypeAnime,
};

@interface PTAPIManager : NSObject

+ (instancetype)sharedManager;

- (void)showInfoWithType:(PTItemType)type
                  withId:(NSString *)imdbId
                 success:(PTAPIManagerSuccessItem)success
                 failure:(PTAPIManagerFailure)failure;

- (void)searchForShowWithType:(PTItemType)type
                         name:(NSString *)name
                      success:(PTAPIManagerSuccessItems)success
                      failure:(PTAPIManagerFailure)failure;

- (void)topShowsWithType:(PTItemType)type
                withPage:(NSUInteger)page
                 success:(PTAPIManagerSuccessItems)success
                 failure:(PTAPIManagerFailure)failure;

// Trakt.tv
/*
+ (NSString *)trakttvAccessToken;
+ (void)updateTrakttvAccessToken:(NSString *)accessToken;
+ (NSURL *)trakttvAuthorizationURL;
- (void)accessTokenWithAuthorizationCode:(NSString *)authorizationCode
                             success:(void(^)(NSString *accessToken))success
                             failure:(PTAPIManagerFailure)failure;

- (void)createListWithName:(NSString *)name
                   success:(PTAPIManagerSuccessNone)success
                   failure:(PTAPIManagerFailure)failure;
*/

@end


================================================
FILE: PopcornTime/Models/PTAPIManager.m
================================================
//
//  PTAPIManager.m
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 2/25/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

#import "PTAPIManager.h"

#import <UIKit/UIKit.h>

NSUInteger const PTAPIManagerResultsLimit = 30;
NSString *const PTAPIManagerMoviesEndPoint = @"http://api.torrentsapi.com/";
NSString *const PTAPIManagerShowsEndPoint = @"https://api-fetch.website/tv/";
NSString *const PTAPIManagerAnimeEndPoint = @"http://ptp.haruhichan.com";

@implementation PTAPIManager

static NSDictionary *YTSHTTPHeaders;

#pragma mark - Public API


+ (void)initialize
{
    YTSHTTPHeaders = @{@"Host": @"eqwww.image.yt"};
}

+ (instancetype)sharedManager
{
    static dispatch_once_t onceToken;
    static PTAPIManager *sharedManager;
    dispatch_once(&onceToken, ^{
        sharedManager = [[PTAPIManager alloc] init];
    });
    return sharedManager;
}

- (void)showInfoWithType:(PTItemType)type
                  withId:(NSString *)imdbId
                 success:(PTAPIManagerSuccessItem)success
                 failure:(PTAPIManagerFailure)failure
{
    switch (type) {
        case PTItemTypeMovie: { [self movieInfoWithId:imdbId success:success failure:failure]; break; }
        case PTItemTypeShow: { [self tvSeriesInfoWithId:imdbId success:success failure:failure]; break; }
        case PTItemTypeAnime: { [self animeInfoWithId:imdbId success:success failure:failure]; break; }
        default: break;
    }
}

- (void)searchForShowWithType:(PTItemType)type
                        name:(NSString *)name
                      success:(PTAPIManagerSuccessItems)success
                      failure:(PTAPIManagerFailure)failure
{
    switch (type) {
        case PTItemTypeMovie: { [self searchForMovieWithName:name success:success failure:failure]; break; }
        case PTItemTypeShow: { [self searchForTVSeriesWithName:name success:success failure:failure]; break; }
        case PTItemTypeAnime: { [self searchForAnimeWithName:name success:success failure:failure]; break; }
        default: break;
    }
}

- (void)topShowsWithType:(PTItemType)type
                withPage:(NSUInteger)page
                 success:(PTAPIManagerSuccessItems)success
                 failure:(PTAPIManagerFailure)failure{
    switch (type) {
        case PTItemTypeMovie: { [self topMoviesWithPage:page success:success failure:failure]; break; }
        case PTItemTypeShow: { [self topTVSeriesWithPage:page success:success failure:failure]; break; }
        case PTItemTypeAnime: { [self topAnimeWithPage:page success:success failure:failure]; break; }
        default: break;
    }
}

#pragma mark - Private Methods

- (void)dataFromURL:(NSURL *)URL
            success:(void(^)(id JSONObject))success
            failure:(PTAPIManagerFailure)failure
{
    return [self dataFromURL:URL HTTPheaders:nil success:success failure:failure];
}

- (void)dataFromURL:(NSURL *)URL
            HTTPheaders:(NSDictionary *)HTTPheaders
            success:(void(^)(id JSONObject))success
            failure:(PTAPIManagerFailure)failure
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    if (HTTPheaders) {
        for (NSString *key in HTTPheaders.allKeys) {
            [request addValue:HTTPheaders[key] forHTTPHeaderField:key];
        }
    }
    
    [[[NSURLSession sharedSession] dataTaskWithRequest:request
                                     completionHandler:
      ^(NSData *data, NSURLResponse *response, NSError *error) {
          dispatch_async(dispatch_get_main_queue(), ^{

            [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
              
              void (^handleError)(NSError *) = ^(NSError *error) {
                  if (error) { NSLog(@"%@", error); if (failure) { failure(error); } }
              };
              
              if (error) { handleError(error); return; }
              
              NSError *JSONError;
              id JSONObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&JSONError];
              if (JSONError) { handleError(JSONError); return; }
              
              if (success) { success(JSONObject); };
          });
      }] resume];
}

#pragma mark Movies

- (void)topMoviesWithPage:(NSUInteger)page
                  success:(PTAPIManagerSuccessItems)success
                  failure:(PTAPIManagerFailure)failure
{
    NSString *path = [NSString stringWithFormat:@"list?"
                      "page=%ld&limit=%ld&order_by=desc&sort_by=seeds&with_rt_ratings=true", (long)page + 1, (long)PTAPIManagerResultsLimit];
   
    NSString *URLString = [PTAPIManagerMoviesEndPoint stringByAppendingPathComponent:path];
    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            NSArray *items = [((NSDictionary *)JSONObject) objectForKey:@"MovieList"];
            success(items);
            
        }
    } failure:failure];
}
- (void)movieInfoWithId:(NSString *)imdbId
                success:(PTAPIManagerSuccessItem)success
                failure:(PTAPIManagerFailure)failure
{
    NSString *path = [NSString stringWithFormat:@"list?"
                      "page=1&limit=5&order_by=desc&sort_by=seeds&with_rt_ratings=true"];

//    NSString *path = [NSString stringWithFormat:@"list?id=%@", imdbId];
    NSString *URLString = [PTAPIManagerMoviesEndPoint stringByAppendingPathComponent:path];
    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            NSDictionary *items = [((NSDictionary *)JSONObject) objectForKey:@"MovieList"];
            for(id key in items) {
                NSString *id = [key objectForKey:@"id"];
                if([id isEqualToString:imdbId]) {
                    success(key);
                    break;
                }
            }
//            success(items);
        }
    } failure:failure];
}

- (void)searchForMovieWithName:(NSString *)name
                       success:(PTAPIManagerSuccessItems)success
                       failure:(PTAPIManagerFailure)failure
{
    NSString *path = [[NSString stringWithFormat:@"list?sort_by=seeds&limit=%ld&with_rt_ratings=true&page=1&keywords=%@", (long)PTAPIManagerResultsLimit, name]
                      stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *URLString = [PTAPIManagerMoviesEndPoint stringByAppendingPathComponent:path];
    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            NSArray *items = [((NSDictionary *)JSONObject) objectForKey:@"MovieList"];
            success(items);
        }
    } failure:failure];
}

#pragma mark TVSeries

- (void)topTVSeriesWithPage:(NSUInteger)page
                 success:(PTAPIManagerSuccessItems)success
                 failure:(PTAPIManagerFailure)failure
{
    NSString *path = [NSString stringWithFormat:@"shows/%ld?limit=%lu", (long)page + 1, (long)PTAPIManagerResultsLimit];
    NSString *URLString = [PTAPIManagerShowsEndPoint stringByAppendingPathComponent:path];
    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            success((NSArray *)JSONObject);
        }
    } failure:failure];
}

- (void)tvSeriesInfoWithId:(NSString *)imdbId
                   success:(PTAPIManagerSuccessItem)success
                   failure:(PTAPIManagerFailure)failure
{
    NSString *path = [NSString stringWithFormat:@"show/%@", imdbId];
    NSString *URLString = [PTAPIManagerShowsEndPoint stringByAppendingPathComponent:path];
    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            success((NSDictionary *)JSONObject);
        }
    } failure:failure];
}

- (void)searchForTVSeriesWithName:(NSString *)name
                      success:(PTAPIManagerSuccessItems)success
                      failure:(PTAPIManagerFailure)failure
{
    NSString *path = [[NSString stringWithFormat:@"shows/1?limit=%ld&keywords=%@&sort=seeds", (long)PTAPIManagerResultsLimit, name]
                      stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *URLString = [PTAPIManagerShowsEndPoint stringByAppendingPathComponent:path];
    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            success((NSArray *)JSONObject);
        }
    } failure:failure];
}

#pragma mark Anime

- (void)topAnimeWithPage:(NSUInteger)page
                 success:(PTAPIManagerSuccessItems)success
                 failure:(PTAPIManagerFailure)failure
{
    NSString *path = [[NSString stringWithFormat:@"list.php?page=%ld&limit=%ld&sort=popularity&type=All", (long)page, (long)PTAPIManagerResultsLimit]
                      stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *URLString = [PTAPIManagerAnimeEndPoint stringByAppendingPathComponent:path];

    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            success((NSArray *)JSONObject);
        }
    } failure:failure];
}

- (void)animeInfoWithId:(NSString *)imdbId
                success:(PTAPIManagerSuccessItem)success
                failure:(PTAPIManagerFailure)failure
{
    NSString *path = [NSString stringWithFormat:@"anime.php?id=%@", imdbId];
    NSString *URLString = [PTAPIManagerAnimeEndPoint stringByAppendingPathComponent:path];
    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            success((NSDictionary *)JSONObject);
        }
    } failure:failure];
}

- (void)searchForAnimeWithName:(NSString *)name
                       success:(PTAPIManagerSuccessItems)success
                       failure:(PTAPIManagerFailure)failure {
    
    NSString *path = [[NSString stringWithFormat:@"/list.php?search=%@&limit=%ld&sort=popularity&type=All",
                       [name stringByReplacingOccurrencesOfString:@" " withString:@"+"], (long)PTAPIManagerResultsLimit]
                      stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *URLString = [PTAPIManagerAnimeEndPoint stringByAppendingPathComponent:path];
    
    [self dataFromURL:[NSURL URLWithString:URLString] success:^(id JSONObject) {
        if (success) {
            success((NSArray *)JSONObject);
        }
    } failure:failure];
}

#pragma mark - Trakt.tv

/*

NSString *const PTAPIManagerTrakttvAccessTokenKey = @"TrakttvAccessToken";

NSString *const PTAPIManagerTrakttvAPIEndPoint = @"http://api.trakt.tv";
NSString *const PTAPIManagerTrakttvAPIKey = @"df8d400233727be104e5caf40e07d785b6963c0e194dcbd24f806e8a4e243167";
NSString *const PTAPIManagerTrakttvAPIVersion = @"2";

NSString *const PTAPIManagerTrakttvClientId = @"df8d400233727be104e5caf40e07d785b6963c0e194dcbd24f806e8a4e243167";
NSString *const PTAPIManagerTrakttvClientSecret = @"1a98885c5271f7162ac51b2c1dd09decc55df127f5e1b29af533d35eee5df9b2";
NSString *const PTAPIManagerTrakttvRedirectURL = @"urn:ietf:wg:oauth:2.0:oob";

+ (NSString *)trakttvAccessToken
{
    return [[NSUserDefaults standardUserDefaults] objectForKey:PTAPIManagerTrakttvAccessTokenKey];
}

+ (void)updateTrakttvAccessToken:(NSString *)accessToken
{
    [[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:PTAPIManagerTrakttvAccessTokenKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

+ (NSURL *)trakttvAuthorizationURL
{
    NSString *authPath = [NSString stringWithFormat:@"http://trakt.tv/oauth/authorize?client_id=%@&redirect_uri=%@&response_type=code",
                          PTAPIManagerTrakttvClientId,
                          PTAPIManagerTrakttvRedirectURL];
    return [NSURL URLWithString:authPath];
}

- (void)trakttvPerformRequestWithAPIMethod:(NSString *)APIMethod
                                HTTPMethod:(NSString *)HTTPMethod
                           HTTPBodyPayload:(NSDictionary *)HTTPBodyPayload
                             OAuthRequired:(BOOL)OAuthRequired
                                   success:(void(^)(id JSONObject))success
                                   failure:(PTAPIManagerFailure)failure
{
    NSString *path = [PTAPIManagerTrakttvAPIEndPoint stringByAppendingPathComponent:APIMethod];
    NSURL *URL = [NSURL URLWithString:path];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    request.HTTPMethod = HTTPMethod;
    
    // Configure headers
    [request addValue:@"application/json" forHTTPHeaderField:@"Content-type"];
    [request addValue:PTAPIManagerTrakttvAPIKey forHTTPHeaderField:@"trakt-api-key"];
    [request addValue:PTAPIManagerTrakttvAPIVersion forHTTPHeaderField:@"trakt-api-version"];
    
    if (OAuthRequired) {
        NSString *bearerToken = [NSString stringWithFormat:@"Bearer [%@]", [PTAPIManager trakttvAccessToken]];
        [request addValue:bearerToken forHTTPHeaderField:@"Authorization"];
    }

    void (^handleError)(NSError *) = ^(NSError *error) {
        if (error) { NSLog(@"%@", error); if (failure) { failure(error); } }
    };
    
    // Configure body
    NSError *JSONError;
    NSData *JSONBody = [NSJSONSerialization dataWithJSONObject:HTTPBodyPayload options:0 error:&JSONError];
    handleError(JSONError);
    request.HTTPBody = JSONBody;
    
    [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
      ^(NSData *data, NSURLResponse *response, NSError *error) {
          dispatch_async(dispatch_get_main_queue(), ^{
              if (error) { handleError(error); return; }
              
              NSError *JSONError;
              id JSONObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&JSONError];
              if (JSONError) { handleError(JSONError); return; }
              
              if (success) { success(JSONObject); }
          });
      }] resume];
}

- (void)accessTokenWithAuthorizationCode:(NSString *)authorizationCode
                                 success:(void(^)(NSString *accessToken))success
                                 failure:(PTAPIManagerFailure)failure
{
    NSString *APIMethod = @"oauth/token";
    NSDictionary *HTTPBodyPayload = @{@"code": authorizationCode,
                                      @"client_id": PTAPIManagerTrakttvClientId,
                                      @"client_secret": PTAPIManagerTrakttvClientSecret,
                                      @"redirect_uri": PTAPIManagerTrakttvRedirectURL,
                                      @"grant_type": @"authorization_code"};
    
    [self trakttvPerformRequestWithAPIMethod:APIMethod
                                  HTTPMethod:@"POST"
                             HTTPBodyPayload:HTTPBodyPayload
                               OAuthRequired:NO
                                     success:^(id JSONObject) {
                                         if (success) {
                                             success([((NSDictionary *)JSONObject) objectForKey:@"access_token"]);
                                         }
                                     }
                                     failure:failure];
}

- (void)createListWithName:(NSString *)name
                   success:(PTAPIManagerSuccessNone)success
                   failure:(PTAPIManagerFailure)failure
{
    NSString *APIMethod = @"users/me/lists";
    NSDictionary *HTTPBodyPayload = @{@"name": @"ololo",
                                      @"description": @"ololo",
                                      @"privacy": @"private",
                                      @"display_numbers": @"false",
                                      @"allow_comments": @"true"};

    [self trakttvPerformRequestWithAPIMethod:APIMethod
                                  HTTPMethod:@"POST"
                             HTTPBodyPayload:HTTPBodyPayload
                               OAuthRequired:YES
    success:nil failure:failure];
}

 */
 
@end


================================================
FILE: PopcornTime/Models/PTTorrentStreamer.h
================================================
//
//  PTTorrentStreamer.h
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 2/23/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef struct {
    float bufferingProgress;
    float totalProgreess;
    int downloadSpeed;
    int upoadSpeed;
    int seeds;
    int peers;
} PTTorrentStatus;

typedef void (^PTTorrentStreamerProgress)(PTTorrentStatus status);
typedef void (^PTTorrentStreamerReadyToPlay)(NSURL *videoFileURL);
typedef void (^PTTorrentStreamerFailure)(NSError *error);

@interface PTTorrentStreamer : NSObject

+ (instancetype)sharedStreamer;

- (void)startStreamingFromFileOrMagnetLink:(NSString *)filePathOrMagnetLink
                                  progress:(PTTorrentStreamerProgress)progreess
                               readyToPlay:(PTTorrentStreamerReadyToPlay)readyToPlay
                                   failure:(PTTorrentStreamerFailure)failure;

- (void)cancelStreaming;

@end


================================================
FILE: PopcornTime/Models/PTTorrentStreamer.mm
================================================
//
//  PTTorrentStreamer.m
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 2/23/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

#import "PTTorrentStreamer.h"

#import <UIKit/UIKit.h>

#import <string>
#import <libtorrent/session.hpp>
#import <libtorrent/alert.hpp>
#import <libtorrent/alert_types.hpp>

#import <CocoaSecurity/CocoaSecurity.h>

using namespace libtorrent;

@interface PTTorrentStreamer()
@property (nonatomic, strong) dispatch_queue_t alertsQueue;
@property (nonatomic, getter=isAlertsLoopActive) BOOL alertsLoopActive;
@property (nonatomic, strong) NSString *savePath;
@property (nonatomic, getter=isDownloading) BOOL downloading;
@property (nonatomic, getter=isStreaming) BOOL streaming;

@property (nonatomic, copy) PTTorrentStreamerProgress progressBlock;
@property (nonatomic, copy) PTTorrentStreamerReadyToPlay readyToPlayBlock;
@property (nonatomic, copy) PTTorrentStreamerFailure failureBlock;
@end

@implementation PTTorrentStreamer
{
    session *_session;
    std::vector<int> required_pieces;
}

+ (instancetype)sharedStreamer
{
    static dispatch_once_t onceToken;
    static PTTorrentStreamer *sharedStreamer;
    dispatch_once(&onceToken, ^{
        sharedStreamer = [[PTTorrentStreamer alloc] init];
    });
    return sharedStreamer;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setupSession];
    }
    return self;
}

#pragma mark - 

+ (NSString *)downloadsDirectory
{
    NSString *downloadsDirectoryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"Downloads"];
    if (![[NSFileManager defaultManager] fileExistsAtPath:downloadsDirectoryPath]) {
        NSError *error;
        [[NSFileManager defaultManager] createDirectoryAtPath:downloadsDirectoryPath
                                  withIntermediateDirectories:YES
                                                   attributes:nil
                                                        error:&error];
        if (error) {
            NSLog(@"%@", error);
            return nil;
        }
    }
    return downloadsDirectoryPath;
}

- (void)setupSession
{
//    _session = new session(fingerprint("PopcornTime", 1, 0, 0, 0),
//                           std::make_pair(6881, 6889),
//                           0,
//                           session::start_default_features | session::add_default_plugins,
//                           alert::all_categories);

    error_code ec;

    _session = new session();
    _session->set_alert_mask(alert::all_categories);
    _session->listen_on(std::make_pair(6881, 6889), ec);
    if (ec) {
        NSLog(@"failed to open listen socket: %s", ec.message().c_str());
    }
    
    session_settings settings = _session->settings();
    settings.announce_to_all_tiers = true;
    settings.announce_to_all_trackers = true;
    settings.prefer_udp_trackers = false;
    settings.max_peerlist_size = 0;
    _session->set_settings(settings);
}

- (void)startStreamingFromFileOrMagnetLink:(NSString *)filePathOrMagnetLink
                                  progress:(PTTorrentStreamerProgress)progreess
                               readyToPlay:(PTTorrentStreamerReadyToPlay)readyToPlay
                                   failure:(PTTorrentStreamerFailure)failure;
{
    self.progressBlock = progreess;
    self.readyToPlayBlock = readyToPlay;
    self.failureBlock = failure;

    self.alertsQueue = dispatch_queue_create("com.popcorntime.ios.torrentstreamer.alerts", DISPATCH_QUEUE_SERIAL);
    self.alertsLoopActive = YES;
    dispatch_async(self.alertsQueue, ^{
        [self alertsLoop];
    });
    
    error_code ec;
    add_torrent_params tp;
    
    NSString *MD5String = nil;
    
    if ([filePathOrMagnetLink hasPrefix:@"magnet"]) {
        NSString *magnetLink = filePathOrMagnetLink;
        magnetLink = [magnetLink stringByAppendingString:@"&tr=udp://open.demonii.com:1337"
                                                          "&tr=udp://tracker.coppersurfer.tk:6969"];
        tp.url = std::string([magnetLink UTF8String]);
        
        MD5String = [CocoaSecurity md5:magnetLink].hexLower;
    } else {
        NSString *filePath = filePathOrMagnetLink;
        if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
            NSData *fileData = [NSData dataWithContentsOfFile:filePath];
            MD5String = [CocoaSecurity md5WithData:fileData].hexLower;
            
            tp.ti = new torrent_info([filePathOrMagnetLink UTF8String], ec);
            if (ec) {
                NSLog(@"%s", ec.message().c_str());
                return;
            }
        } else {
            NSLog(@"File doesn't exists at path: %@", filePath);
            return;
        }
    }

    NSString *halfMD5String = [MD5String substringToIndex:16];
    self.savePath = [[PTTorrentStreamer downloadsDirectory] stringByAppendingPathComponent:halfMD5String];
    
    NSError *error;
    [[NSFileManager defaultManager] createDirectoryAtPath:self.savePath
                              withIntermediateDirectories:YES
                                               attributes:nil
                                                    error:&error];
    if (error) {
        NSLog(@"Can't create directory at path: %@", self.savePath);
        return;
    }

    tp.save_path = std::string([self.savePath UTF8String]);
    tp.storage_mode = storage_mode_allocate;
    
    torrent_handle th = _session->add_torrent(tp, ec);
    th.set_sequential_download(true);
    
    if (ec) {
        NSLog(@"%s", ec.message().c_str());
        return;
    }
    
    self.downloading = YES;
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

- (void)cancelStreaming
{
    if ([self isDownloading]) {
        self.alertsQueue = nil;
        self.alertsLoopActive = NO;

        std::vector<torrent_handle> ths = _session->get_torrents();
        for(std::vector<torrent_handle>::size_type i = 0; i != ths.size(); i++) {
            _session->remove_torrent(ths[i], session::delete_files);
        }
        
        required_pieces.clear();
        
        self.progressBlock = nil;
        self.readyToPlayBlock = nil;
        self.failureBlock = nil;

        NSError *error;
        [[NSFileManager defaultManager] removeItemAtPath:self.savePath error:&error];
        if (error) NSLog(@"%@", error);
        
        self.savePath = nil;
        
        self.streaming = NO;
        self.downloading = NO;
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    }
}

#pragma mark - Alerts Loop

#define ALERTS_LOOP_WAIT_MILLIS 500
#define MIN_PIECES 15
#define PIECE_DEADLINE_MILLIS 100
#define LIBTORRENT_PRIORITY_SKIP 0
#define LIBTORRENT_PRIORITY_MAXIMUM 7

- (void)alertsLoop
{
    std::deque<alert *> deque;
    time_duration max_wait = milliseconds(ALERTS_LOOP_WAIT_MILLIS);
    
    while ([self isAlertsLoopActive])
    {
        const alert *ptr = _session->wait_for_alert(max_wait);
        if (ptr != nullptr) {
            _session->pop_alerts(&deque);
            for (std::deque<alert *>::iterator it=deque.begin(); it != deque.end(); ++it) {
                std::unique_ptr<alert> alert(*it);
//                NSLog(@"type:%d msg:%s", alert->type(), alert->message().c_str());
                switch (alert->type()) {
                    case metadata_received_alert::alert_type:
                        [self metadataReceivedAlert:(metadata_received_alert *)alert.get()];
                        break;
                    case block_finished_alert::alert_type:
                        [self pieceFinishedAlert:(piece_finished_alert *)alert.get()];
                        break;
                    // In case the video file is already fully downloaded
                    case torrent_finished_alert::alert_type:
                        [self torrentFinishedAlert:(torrent_finished_alert *)alert.get()];
                        break;
                    default: break;
                }
            }
            deque.clear();
        }
    }
}

- (void)prioritizeNextPieces:(torrent_handle)th
{
    int next_required_piece = required_pieces[MIN_PIECES-1]+1;
    required_pieces.clear();
    
    boost::intrusive_ptr<const torrent_info> ti = th.torrent_file();
    
    for (int i=next_required_piece; i<next_required_piece+MIN_PIECES; i++) {
        if (i < ti->num_pieces()) {
            th.piece_priority(i, LIBTORRENT_PRIORITY_MAXIMUM);
            th.set_piece_deadline(i, PIECE_DEADLINE_MILLIS, torrent_handle::alert_when_available);
            required_pieces.push_back(i);
        }
    }
}

- (void)processTorrent:(torrent_handle)th
{
    if (![self isStreaming]) {
        self.streaming = YES;
        if (self.readyToPlayBlock) {
            boost::intrusive_ptr<const torrent_info> ti = th.torrent_file();
            int file_index = [self indexOfLargestFileInTorrent:th];
            file_entry fe = ti->file_at(file_index);
            std::string path = fe.path;
            
            NSString *fileName = [NSString stringWithCString:path.c_str() encoding:NSUTF8StringEncoding];
            NSURL *fileURL = [NSURL fileURLWithPath:[self.savePath stringByAppendingPathComponent:fileName]];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                self.readyToPlayBlock(fileURL);
            });
        }
    }
}

- (int)indexOfLargestFileInTorrent:(torrent_handle)th
{
    boost::intrusive_ptr<const torrent_info> ti = th.torrent_file();
    int files_count = ti->num_files();
    if (files_count > 1) {
        size_type largest_size = -1;
        int largest_file_index = -1;
        for (int i=0; i<files_count; i++) {
            file_entry fe = ti->file_at(i);
            if (fe.size > largest_size) {
                largest_size = fe.size;
                largest_file_index = i;
            }
        }
        return largest_file_index;
    }
    return 0;
}

#pragma mark - Logging

- (void)logPiecesStatus:(torrent_handle)th
{
    NSString *pieceStatus = @"";
    boost::intrusive_ptr<const torrent_info> ti = th.torrent_file();
    for(std::vector<int>::size_type i=0; i!=required_pieces.size(); i++) {
        int piece = required_pieces[i];
        pieceStatus = [pieceStatus stringByAppendingFormat:@"%d:%d ", piece, th.have_piece(piece)];
    }
    NSLog(@"%@", pieceStatus);
}

- (void)logTorrentStatus:(PTTorrentStatus)status
{
    NSString *speedString = [NSByteCountFormatter stringFromByteCount:status.downloadSpeed
                                                           countStyle:NSByteCountFormatterCountStyleBinary];
    NSLog(@"%.0f%%, %.0f%%, %@/s, %d, %d",
          status.bufferingProgress*100, status.totalProgreess*100,
          speedString, status.seeds, status.peers);
}

#pragma mark - Alerts

- (void)metadataReceivedAlert:(metadata_received_alert *)alert
{
    torrent_handle th = alert->handle;
    int file_index = [self indexOfLargestFileInTorrent:th];

    std::vector<int> file_priorities = th.file_priorities();
    std::fill(file_priorities.begin(), file_priorities.end(), LIBTORRENT_PRIORITY_SKIP);
    file_priorities[file_index] = LIBTORRENT_PRIORITY_MAXIMUM;
    th.prioritize_files(file_priorities);
    
    boost::intrusive_ptr<const torrent_info> ti = th.torrent_file();
    int first_piece = ti->map_file(file_index, 0, 0).piece;
    for (int i=first_piece; i<first_piece+MIN_PIECES; i++) {
        required_pieces.push_back(i);
    }

    size_type file_size = ti->file_at(file_index).size;
    int last_piece = ti->map_file(file_index, file_size-1, 0).piece;
    required_pieces.push_back(last_piece);
    
    for (int i=1; i<10; i++) {
        required_pieces.push_back(last_piece-i);
    }
    
    for(std::vector<int>::size_type i=0; i!=required_pieces.size(); i++) {
        int piece = required_pieces[i];
        th.piece_priority(piece, LIBTORRENT_PRIORITY_MAXIMUM);
        th.set_piece_deadline(piece, PIECE_DEADLINE_MILLIS, torrent_handle::alert_when_available);
    }
}

- (void)pieceFinishedAlert:(piece_finished_alert *)alert
{
    torrent_handle th = alert->handle;
    torrent_status status = th.status();
    
    int requiredPiecesDownloaded = 0;
    BOOL allRequiredPiecesDownloaded = YES;
    for(std::vector<int>::size_type i=0; i!=required_pieces.size(); i++) {
        int piece = required_pieces[i];
        if (th.have_piece(piece)) {
            requiredPiecesDownloaded++;
        } else {
            allRequiredPiecesDownloaded = NO;            
        }
    }
    
    [self logPiecesStatus:th];
    
    int requiredPieces = (int)required_pieces.size();
    float bufferingProgress = 1.0 - (requiredPieces-requiredPiecesDownloaded)/(float)requiredPieces;
    
    PTTorrentStatus torrentStatus = {bufferingProgress,
                                    status.progress,
                                    status.download_rate,
                                    status.upload_rate,
                                    status.num_seeds,
                                    status.num_peers};
    [self logTorrentStatus:torrentStatus];
    
    if (self.progressBlock) {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.progressBlock(torrentStatus);
        });
    }
    
    if (allRequiredPiecesDownloaded) {
        [self prioritizeNextPieces:th];
        [self processTorrent:th];
    }
}

- (void)torrentFinishedAlert:(torrent_finished_alert *)alert
{
    [self processTorrent:alert->handle];
}

@end


================================================
FILE: PopcornTime/Models/ParseManager.swift
================================================
//
//  ParseManager.swift
//  
//
//  Created by Andriy K. on 6/23/15.
//
//

import UIKit

class ParseShowData: NSObject {
    
    private var collection = [String : PFObject]()
    
    convenience init(episodesFromParse: [PFObject]) {
        self.init()
        for episode in episodesFromParse {
            let seasonIndex = episode.objectForKey(ParseManager.sharedInstance.seasonKey) as! Int
            let episodeIndex = episode.objectForKey(ParseManager.sharedInstance.episodeKey) as! Int
            let key = dictKey(seasonIndex, episode: episodeIndex)
            collection[key] = episode
        }
    }
    
    func isEpisodeWatched(season: Int, episode: Int) -> Bool {
        let key = dictKey(season, episode: episode)
        if let episode = collection[key] {
            if let isWatched = episode.objectForKey(ParseManager.sharedInstance.watchedKey) as? Bool {
                return isWatched
            }
        }
        return false
    }
    
    private func dictKey(season: Int, episode: Int) -> String {
        return "\(season)_\(episode)"
    }
    
}

class ParseManager: NSObject {
    
    static let sharedInstance = ParseManager()
    
    let showClassName = "Show"
    let episodeClassName = "Episode"
    let showIdKey = "showId"
    let userKey = "user"
    let titleKey = "title"
    let seasonKey = "season"
    let episodeKey = "episodeNumber"
    let showKey = "show"
    let watchedKey = "watched"
    
    private override init() {
    }
    
    // MARK: - Public API
    
    var user: PFUser? {
        return PFUser.currentUser()
    }
    
    func markEpisode(episodeInfo: Episode, basicInfo: BasicInfo) {
        if let user = user {
            let query = PFQuery(className:showClassName)
            query.whereKey(userKey, equalTo:user)
            query.whereKey(showIdKey, equalTo:basicInfo.identifier)
            query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
                
                var show: PFObject
                
                if let object = objects?.first as PFObject? {
                    show = object
                } else {
                    show = PFObject(className: self.showClassName)
                    show.setObject(basicInfo.identifier, forKey: self.showIdKey)
                    if let title = basicInfo.title {
                        show.setObject(title, forKey: self.titleKey)
                    }
                    let relation = show.relationForKey(self.userKey)
                    relation.addObject(user)
                }
                
                show.saveInBackgroundWithBlock({ (success, error) -> Void in

                    let queryEpisode = PFQuery(className:self.episodeClassName)
                    queryEpisode.whereKey(self.seasonKey, equalTo:episodeInfo.seasonNumber)
                    queryEpisode.whereKey(self.episodeKey, equalTo:episodeInfo.episodeNumber)
                    queryEpisode.whereKey(self.showKey, equalTo: show)
                    
                    queryEpisode.findObjectsInBackgroundWithBlock { (episodes, episodeError) -> Void in

                        var episode: PFObject
                        
                        if let ep = episodes?.first as PFObject? {
                            episode = ep
                        } else {
                            let newEpisode = PFObject(className: self.episodeClassName)
                            let relationShow = newEpisode.relationForKey(self.showKey)
                            relationShow.addObject(show)
                            newEpisode.setObject(episodeInfo.seasonNumber, forKey: self.seasonKey)
                            newEpisode.setObject(episodeInfo.episodeNumber, forKey: self.episodeKey)
                            episode = newEpisode
                        }
                        episode.setObject(true, forKey: self.watchedKey)
                        
                        episode.saveInBackgroundWithBlock(nil)
                    }
                })
            }
        }
    }
    
    /// Mark  [Episode] as watched on Parse.
    func markEpisodes(episodesInfo: [Episode], basicInfo: BasicInfo, completionHandler: PFBooleanResultBlock?) {
        
        if episodesInfo.count == 0 {
            return
        }

        let episodeNumbers = episodesInfo.map(){ episode in
            return episode.episodeNumber
        }
        let seasonNumber = episodesInfo.first!.seasonNumber

        
        if let user = user {
            let query = PFQuery(className:showClassName)
            query.whereKey(userKey, equalTo:user)
            query.whereKey(showIdKey, equalTo:basicInfo.identifier)
            query.findObjectsInBackgroundWithBlock {
                (objects, error) -> Void in

                var show: PFObject

                if let object = objects?.first as PFObject? {
                    show = object
                } else {
                    show = PFObject(className: self.showClassName)
                    show.setObject(basicInfo.identifier, forKey: self.showIdKey)
                    if let title = basicInfo.title {
                        show.setObject(title, forKey: self.titleKey)
                    }
                    let relation = show.relationForKey(self.userKey)
                    relation.addObject(user)
                }

                show.saveInBackgroundWithBlock({ (success, error) -> Void in
                    let queryEpisode = PFQuery(className:self.episodeClassName)
                    queryEpisode.whereKey(self.seasonKey, equalTo: seasonNumber)
                    queryEpisode.whereKey(self.episodeKey, containedIn: episodeNumbers)
                    queryEpisode.whereKey(self.showKey, equalTo: show)
                    
                    queryEpisode.findObjectsInBackgroundWithBlock { (results, episodeError) -> Void in
                        
                        var marked = [UInt]()
                        var pfObjects = [PFObject]()
                        
                        if let parseEpisodes = results as [PFObject]? {
                            print("\(parseEpisodes.count): episodes already on Parse")
                            for parseEp in parseEpisodes {
                                parseEp.setObject(true, forKey: self.watchedKey)
                                if let parseEpNumber = parseEp.objectForKey(self.episodeKey) as? UInt {
                                    marked.append(parseEpNumber)
                                    pfObjects.append(parseEp)
                                    print("parse ep:\(parseEpNumber) marked")
                                }
                            }
                        }
            
                        
                        for ep in episodesInfo {
                            if marked.contains(ep.episodeNumber) == false {
                                let newEpisode = PFObject(className: self.episodeClassName)
                                let relationShow = newEpisode.relationForKey(self.showKey)
                                relationShow.addObject(show)
                                newEpisode.setObject(ep.seasonNumber, forKey: self.seasonKey)
                                newEpisode.setObject(ep.episodeNumber, forKey: self.episodeKey)
                                newEpisode.setObject(true, forKey: self.watchedKey)
                                marked.append(ep.episodeNumber)
                                pfObjects.append(newEpisode)
                                print("ep:\(ep.episodeNumber) marked")
                            }
                        }
                        
                        PFObject.saveAllInBackground(pfObjects, block: completionHandler)
                    }
                })
            }
        }
    }
    
    func parseEpisodesData(basicInfo: BasicInfo, handler: (ParseShowData) -> Void) {
        if let user = user {
            let query = PFQuery(className: showClassName)
            query.whereKey(userKey, equalTo: user)
            query.whereKey(showIdKey, equalTo:basicInfo.identifier)
            query.findObjectsInBackgroundWithBlock({ (results, error) -> Void in
                if let show = results?.first as PFObject? {
                    let queryEpisode = PFQuery(className: self.episodeClassName)
                    queryEpisode.whereKey(self.showKey, equalTo: show)
                    do {
                        let episodes = try queryEpisode.findObjects() as [PFObject]
                        let parserData = ParseShowData(episodesFromParse: episodes)
                        handler(parserData)
                    } catch let error as  NSError {
                        print(error)
                    }
                }
            })
        }
    }
    
}


================================================
FILE: PopcornTime/Models/Show.swift
================================================
//
//  Show.swift
//  PopcornTime
//
//  Created by Danylo Kostyshyn on 3/19/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import Foundation

class Show: BasicInfo {
    var seasons = [Season]()

    func thumbnail(_ original: String) -> String {
        return original.replacingOccurrences(of: "original", with: "thumb",
            options: NSString.CompareOptions.caseInsensitive, range: nil)
    }
    
    required init(dictionary: [AnyHashable: Any]) {
        super.init(dictionary: dictionary)
        
        identifier = dictionary["imdb_id"] as! String
        title = dictionary["title"] as? String
        year = dictionary["year"] as? String
        
        if let imagesDict = dictionary["images"] as? NSDictionary {
            images = [Image]()
            if let banner = imagesDict["banner"] as? String {
                let URL = Foundation.URL(string: thumbnail(banner))
                let image = Image(URL: URL!, type: .banner)
                images.append(image)
            }
            if let fanart = imagesDict["fanart"] as? String {
                let URL = Foundation.URL(string: thumbnail(fanart))
                let image = Image(URL: URL!, type: .fanart)
                images.append(image)
            }
            if let poster = imagesDict["poster"] as? String {
                let URL = Foundation.URL(string: thumbnail(poster))
                let image = Image(URL: URL!, type: .poster)
                images.append(image)
            }
            
            smallImage = images.filter({$0.type == ImageType.poster}).first
            bigImage = images.filter({$0.type == ImageType.fanart}).first
        }
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }

    override func update(_ dictionary: [AnyHashable: Any]) {
        synopsis = dictionary["synopsis"] as? String
        
        seasons.removeAll(keepingCapacity: true)
        var allEpisodes = [Episode]()
        var allSeasonsNumbers = [UInt:Bool]()
        
        guard let episodesDicts = dictionary["episodes"] as? [[AnyHashable: Any]] else { return }
        for episodeDict in episodesDicts {

            var videos = [Video]()

            if let torrents = episodeDict["torrents"] as? [String : NSDictionary] {
                for torrent in torrents {
                    let quality = torrent.0
                    if quality == "0" {
                        continue
                    }
                    
                    let url = torrent.1["url"] as! String
                    
                    let video = Video(name: nil, quality: quality, size: 0, duration: 0, subGroup: nil, magnetLink: url)
                    videos.append(video)
                }
            }
            
            videos = videos.sorted(by: { (a, b) -> Bool in
                var aQuality: Int = 0
                Scanner(string: a.quality!).scanInt(&aQuality)

                var bQuality: Int = 0
                Scanner(string: b.quality!).scanInt(&bQuality)
                
                return aQuality < bQuality
            })

            let seasonNumber = (episodeDict["season"] as! UInt)
            if (allSeasonsNumbers[seasonNumber] == nil) {
                allSeasonsNumbers[seasonNumber] = true
            }
            
            let title = episodeDict["title"] as? String
            let episodeNumber = (episodeDict["episode"] as! UInt)

            let synopsis = episodeDict["overview"] as? String
            let episode = Episode(title: title, desc: synopsis, seasonNumber: seasonNumber, episodeNumber: episodeNumber, videos: videos)
            allEpisodes.append(episode)
        }
        
        var seasonsNumbers = Array(allSeasonsNumbers.keys)
        seasonsNumbers.sort(by: { (a, b) -> Bool in
            return a < b
        })
        
        for seasonNumber in seasonsNumbers {
            let seasonEpisodes = allEpisodes.filter({ (episode) -> Bool in
                return episode.seasonNumber == seasonNumber
            })
            
            if seasonEpisodes.count > 0{
                let season = Season(seasonNumber: seasonNumber, episodes: seasonEpisodes)
                seasons.append(season)
            }
        }
    }
}

extension Show: ContainsEpisodes {
    func episodeFor(seasonIndex: Int, episodeIndex: Int) -> Episode {
        let episode = seasons[seasonIndex].episodes[episodeIndex]
        return episode
    }
    
    func episodesFor(seasonIndex: Int) -> [Episode] {
        return seasons[seasonIndex].episodes
    }
}


================================================
FILE: PopcornTime/PopcornTime-Bridging-Header.h
================================================
//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "PTAPIManager.h"
#import "PTTorrentStreamer.h"
#import "VDLPlaybackViewController.h"
#import <CocoaSecurity/CocoaSecurity.h>
#import <SDWebImage/UIImageView+WebCache.h>
#import <SDWebImage/SDWebImageDownloader.h>


================================================
FILE: PopcornTime/Resources/Images.xcassets/AnimeIcon.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "anime.png"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "20x20",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "29x29",
      "scale" : "3x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "40x40",
      "scale" : "3x"
    },
    {
      "size" : "60x60",
      "idiom" : "iphone",
      "filename" : "AppIcon60@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "iphone",
      "size" : "60x60",
      "scale" : "3x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "20x20",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "29x29",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "1x"
    },
    {
      "idiom" : "ipad",
      "size" : "40x40",
      "scale" : "2x"
    },
    {
      "size" : "76x76",
      "idiom" : "ipad",
      "filename" : "AppIcon76.png",
      "scale" : "1x"
    },
    {
      "size" : "76x76",
      "idiom" : "ipad",
      "filename" : "AppIcon76@2x.png",
      "scale" : "2x"
    },
    {
      "idiom" : "ipad",
      "size" : "83.5x83.5",
      "scale" : "2x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/BigLogo.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "popcorn-time-logo.png"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/Contents.json
================================================
{
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/SubwayIconSet/AddToFavoritesIcon.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "icon_087@2x.png"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/SubwayIconSet/FavoritesIcon.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "icon_086@2x.png"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/SubwayIconSet/MoviesIcon.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "icon_0281@2x.png"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/SubwayIconSet/RemoveFromFavoritesIcon.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "icon_088@2x.png"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/SubwayIconSet/SettingsIcon.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "icon_0186@2x.png"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Images.xcassets/SubwayIconSet/ShowsIcon.imageset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "idiom" : "universal",
      "scale" : "2x",
      "filename" : "icon_0304@2x.png"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: PopcornTime/Resources/Launch Screen.xib
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
        <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view contentMode="scaleToFill" id="iN0-l3-epB">
            <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2Lc-RQ-qUE" userLabel="container">
                    <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
                    <subviews>
                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="BigLogo" translatesAutoresizingMaskIntoConstraints="NO" id="bs5-NJ-V6F">
                            <rect key="frame" x="96" y="92" width="288" height="296"/>
                            <constraints>
                                <constraint firstAttribute="width" secondItem="bs5-NJ-V6F" secondAttribute="height" multiplier="245:251" id="Gm1-O8-hkp"/>
                            </constraints>
                        </imageView>
                    </subviews>
                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                    <constraints>
                        <constraint firstItem="bs5-NJ-V6F" firstAttribute="width" secondItem="2Lc-RQ-qUE" secondAttribute="width" multiplier="0.6" id="36t-4H-fXB"/>
                        <constraint firstAttribute="centerY" secondItem="bs5-NJ-V6F" secondAttribute="centerY" id="74X-ZS-r3g"/>
                        <constraint firstAttribute="centerX" secondItem="bs5-NJ-V6F" secondAttribute="centerX" id="wqp-gX-LAI"/>
                    </constraints>
                </view>
            </subviews>
            <color key="backgroundColor" red="0.066666666669999999" green="0.070588235289999995" blue="0.078431372550000003" alpha="1" colorSpace="calibratedRGB"/>
            <constraints>
                <constraint firstAttribute="trailing" secondItem="2Lc-RQ-qUE" secondAttribute="trailing" id="2Bj-4U-BT4"/>
                <constraint firstItem="2Lc-RQ-qUE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="JNM-Yd-jIm"/>
                <constraint firstAttribute="bottom" secondItem="2Lc-RQ-qUE" secondAttribute="bottom" id="JOE-UV-868"/>
                <constraint firstItem="2Lc-RQ-qUE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="xnf-ZZ-Dah"/>
            </constraints>
            <nil key="simulatedStatusBarMetrics"/>
            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
            <point key="canvasLocation" x="404" y="445"/>
        </view>
    </objects>
    <resources>
        <image name="BigLogo" width="490" height="502"/>
    </resources>
</document>


================================================
FILE: PopcornTime/Resources/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="dfX-fY-8T0">
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
    </dependencies>
    <scenes>
        <!--Colorfull Tab Bar Controller-->
        <scene sceneID="go6-cJ-rM0">
            <objects>
                <tabBarController id="dfX-fY-8T0" customClass="ColorfullTabBarController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <nil key="simulatedBottomBarMetrics"/>
                    <tabBar key="tabBar" contentMode="scaleToFill" barStyle="black" id="FiG-nQ-Gwx">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="49"/>
                        <autoresizingMask key="autoresizingMask"/>
                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                    </tabBar>
                    <connections>
                        <segue destination="ZTe-Ju-nKb" kind="relationship" relationship="viewControllers" id="sbB-u7-VOB"/>
                        <segue destination="laf-Ml-R54" kind="relationship" relationship="viewControllers" id="tEU-Ig-sn6"/>
                        <segue destination="Q7f-F1-kvd" kind="relationship" relationship="viewControllers" id="n73-1d-JO5"/>
                        <segue destination="3CV-c3-dhf" kind="relationship" relationship="viewControllers" id="2PJ-Zl-Jde"/>
                    </connections>
                </tabBarController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="mBP-kZ-5Xx" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="112" y="245"/>
        </scene>
        <!--Anime View Controller-->
        <scene sceneID="L5L-Yx-H6c">
            <objects>
                <viewController id="ADj-go-OwF" customClass="AnimeViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="AUE-h9-rJL"/>
                        <viewControllerLayoutGuide type="bottom" id="i2R-TO-heN"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="yYN-t5-Uth">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="N8O-87-354">
                                <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="RCM-ag-Wek">
                                    <size key="itemSize" width="50" height="50"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells/>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="N8O-87-354" firstAttribute="top" secondItem="yYN-t5-Uth" secondAttribute="topMargin" id="Cxr-Mw-YDd"/>
                            <constraint firstAttribute="bottom" secondItem="N8O-87-354" secondAttribute="bottom" id="NZx-Vo-Vo3"/>
                            <constraint firstItem="i2R-TO-heN" firstAttribute="top" secondItem="N8O-87-354" secondAttribute="bottom" id="OUd-9y-xga"/>
                            <constraint firstAttribute="trailing" secondItem="N8O-87-354" secondAttribute="trailing" id="OgF-Q6-JQm"/>
                            <constraint firstItem="N8O-87-354" firstAttribute="leading" secondItem="yYN-t5-Uth" secondAttribute="leading" id="TdS-vL-frL"/>
                        </constraints>
                        <variation key="default">
                            <mask key="constraints">
                                <exclude reference="OUd-9y-xga"/>
                            </mask>
                        </variation>
                    </view>
                    <navigationItem key="navigationItem" id="jQM-dh-vnA"/>
                    <connections>
                        <outlet property="collectionView" destination="N8O-87-354" id="r49-VW-vZu"/>
                        <outlet property="collectionViewLayout" destination="RCM-ag-Wek" id="x5y-ZA-Aax"/>
                        <segue destination="nkV-Ie-GtD" kind="show" identifier="showDetails" id="xDB-pc-cYk"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="FI3-gN-OJO" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1854" y="245"/>
        </scene>
        <!--Shows View Controller-->
        <scene sceneID="BPf-qC-CkQ">
            <objects>
                <viewController id="n2I-Pn-G6j" customClass="ShowsViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="WM1-Br-eA8"/>
                        <viewControllerLayoutGuide type="bottom" id="8Y2-ZI-Ufs"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="IDd-dj-rlb">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="J0Q-3v-mYi">
                                <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="xZ1-3i-1vR">
                                    <size key="itemSize" width="50" height="50"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells/>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="J0Q-3v-mYi" firstAttribute="leading" secondItem="IDd-dj-rlb" secondAttribute="leading" id="99C-v0-KHb"/>
                            <constraint firstAttribute="trailing" secondItem="J0Q-3v-mYi" secondAttribute="trailing" id="9UZ-xj-dko"/>
                            <constraint firstAttribute="bottom" secondItem="J0Q-3v-mYi" secondAttribute="bottom" id="ma4-3V-HrV"/>
                            <constraint firstItem="J0Q-3v-mYi" firstAttribute="top" secondItem="IDd-dj-rlb" secondAttribute="top" id="yal-op-ilq"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" id="VsR-2O-52e"/>
                    <connections>
                        <outlet property="collectionView" destination="J0Q-3v-mYi" id="Bgc-Bn-K8T"/>
                        <outlet property="collectionViewLayout" destination="xZ1-3i-1vR" id="Y07-LZ-q9e"/>
                        <segue destination="6yf-Ps-CJA" kind="show" identifier="showDetails" id="MyM-AG-rLN"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="MVB-v7-qj7" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1854" y="-662"/>
        </scene>
        <!--Anime Details View Controller-->
        <scene sceneID="AiH-fe-1fY">
            <objects>
                <viewController id="nkV-Ie-GtD" customClass="AnimeDetailsViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="QRb-xd-WiJ"/>
                        <viewControllerLayoutGuide type="bottom" id="wed-jV-2Ok"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="RxB-Ov-N2l">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="kC7-OM-puy">
                                <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="ozd-IJ-kA9" customClass="StratchyHeaderLayout" customModule="PopcornTime" customModuleProvider="target">
                                    <size key="itemSize" width="50" height="50"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="5" minY="15" maxX="5" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells>
                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="EpisodeCell" id="X2h-M0-N3e">
                                        <rect key="frame" x="5" y="79" width="50" height="50"/>
                                        <autoresizingMask key="autoresizingMask"/>
                                        <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                            <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                                        </view>
                                        <color key="backgroundColor" red="1" green="0.60942627989999998" blue="0.53172264930000002" alpha="1" colorSpace="calibratedRGB"/>
                                    </collectionViewCell>
                                </cells>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="kC7-OM-puy" firstAttribute="top" secondItem="QRb-xd-WiJ" secondAttribute="bottom" id="7Pu-By-DOS"/>
                            <constraint firstAttribute="bottom" secondItem="kC7-OM-puy" secondAttribute="bottom" id="Ecj-IN-zJN"/>
                            <constraint firstItem="kC7-OM-puy" firstAttribute="top" secondItem="RxB-Ov-N2l" secondAttribute="topMargin" id="He9-Cj-d5V"/>
                            <constraint firstItem="kC7-OM-puy" firstAttribute="leading" secondItem="RxB-Ov-N2l" secondAttribute="leading" id="akD-31-hvB"/>
                            <constraint firstAttribute="trailing" secondItem="kC7-OM-puy" secondAttribute="trailing" id="cVC-Oz-LNb"/>
                        </constraints>
                        <variation key="default">
                            <mask key="constraints">
                                <exclude reference="7Pu-By-DOS"/>
                            </mask>
                        </variation>
                    </view>
                    <connections>
                        <outlet property="collectionView" destination="kC7-OM-puy" id="GQN-oz-xCA"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="17j-G1-ovt" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2650" y="245"/>
        </scene>
        <!--Shows-->
        <scene sceneID="Gqz-GQ-l19">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="Q7f-F1-kvd" sceneMemberID="viewController">
                    <tabBarItem key="tabBarItem" title="Shows" image="ShowsIcon" id="Mo0-0H-mG1"/>
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" id="9UF-I7-giv">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="n2I-Pn-G6j" kind="relationship" relationship="rootViewController" id="2DI-dw-H8V"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="F6Y-qB-7Qf" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1009" y="-662"/>
        </scene>
        <!--Anime-->
        <scene sceneID="eYU-Fj-ZHe">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="3CV-c3-dhf" sceneMemberID="viewController">
                    <tabBarItem key="tabBarItem" title="Anime" image="AnimeIcon" id="3HV-jo-aj6"/>
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" id="jM2-Oi-TbS">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="ADj-go-OwF" kind="relationship" relationship="rootViewController" id="6Pa-6X-tyy"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="eoB-VP-4Xl" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="986" y="253"/>
        </scene>
        <!--Loading View Controller-->
        <scene sceneID="3uL-Yr-CLa">
            <objects>
                <viewController storyboardIdentifier="loadingViewController" id="bUe-YS-Bfo" customClass="LoadingViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="0OC-Vl-SlB"/>
                        <viewControllerLayoutGuide type="bottom" id="a3I-lb-Ai6"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="Ge5-4i-c4F">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3jf-HN-lVz">
                                <rect key="frame" x="0.0" y="20" width="600" height="580"/>
                                <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="Bbw-Ra-hAv">
                                    <rect key="frame" x="0.0" y="0.0" width="600" height="580"/>
                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                    <subviews>
                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Eno-Np-eyT" userLabel="Container View">
                                            <rect key="frame" x="170" y="150" width="260" height="280"/>
                                            <subviews>
                                                <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" fixedFrame="YES" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="iQF-mn-H34">
                                                    <rect key="frame" x="20" y="85" width="220" height="2"/>
                                                </progressView>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="99%" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dyu-uI-e3s" userLabel="Progress Label">
                                                    <rect key="frame" x="55" y="95" width="150" height="21"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Speed: 1.5 MB/s" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZtX-Eh-3Ck" userLabel="Speed Label">
                                                    <rect key="frame" x="55" y="124" width="150" height="21"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Seeds: 20" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="odl-qX-n2O" userLabel="Seeds Label">
                                                    <rect key="frame" x="55" y="153" width="150" height="21"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Peers: 20" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HhI-Ni-8J8" userLabel="Peers Label">
                                                    <rect key="frame" x="55" y="182" width="150" height="21"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="OyV-xC-3a4" userLabel="Cancel Button">
                                                    <rect key="frame" x="95" y="226" width="70" height="30"/>
                                                    <state key="normal" title="Cancel">
                                                        <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
                                                    </state>
                                                    <connections>
                                                        <action selector="cancelButtonPressed:" destination="bUe-YS-Bfo" eventType="touchUpInside" id="O0o-pv-5o4"/>
                                                    </connections>
                                                </button>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Downloading..." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4bR-E2-MXi" userLabel="Status Label">
                                                    <rect key="frame" x="70" y="48" width="120" height="21"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                            </subviews>
                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                                            <constraints>
                                                <constraint firstAttribute="height" constant="280" id="Abb-WO-CaK"/>
                                                <constraint firstAttribute="width" constant="260" id="Azv-Bj-qqf"/>
                                            </constraints>
                                        </view>
                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Movie name - resolution" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BFA-o4-k8D" userLabel="Title Label">
                                            <rect key="frame" x="208" y="35" width="185" height="21"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                            <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                    </subviews>
                                    <constraints>
                                        <constraint firstItem="BFA-o4-k8D" firstAttribute="top" secondItem="Bbw-Ra-hAv" secondAttribute="top" constant="35" id="8GK-gX-IRy"/>
                                        <constraint firstAttribute="centerX" secondItem="BFA-o4-k8D" secondAttribute="centerX" id="HQY-9H-dme"/>
                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="BFA-o4-k8D" secondAttribute="trailing" constant="5" id="TzI-CV-4j1"/>
                                        <constraint firstAttribute="centerY" secondItem="Eno-Np-eyT" secondAttribute="centerY" id="euo-DO-0a6"/>
                                        <constraint firstItem="BFA-o4-k8D" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Bbw-Ra-hAv" secondAttribute="leading" constant="5" id="f3S-uc-t2S"/>
                                        <constraint firstAttribute="centerX" secondItem="Eno-Np-eyT" secondAttribute="centerX" id="fb1-QL-1Gt"/>
                                    </constraints>
                                </view>
                                <blurEffect style="dark"/>
                            </visualEffectView>
                        </subviews>
                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="3jf-HN-lVz" firstAttribute="leading" secondItem="Ge5-4i-c4F" secondAttribute="leadingMargin" id="49U-xF-EQh"/>
                            <constraint firstItem="a3I-lb-Ai6" firstAttribute="top" secondItem="3jf-HN-lVz" secondAttribute="bottom" id="B88-h4-23t"/>
                            <constraint firstAttribute="trailing" secondItem="3jf-HN-lVz" secondAttribute="trailing" id="Dek-k3-qex"/>
                            <constraint firstAttribute="trailingMargin" secondItem="3jf-HN-lVz" secondAttribute="trailing" id="Kog-8l-OhD"/>
                            <constraint firstItem="3jf-HN-lVz" firstAttribute="top" secondItem="0OC-Vl-SlB" secondAttribute="bottom" id="OXD-GG-H1V"/>
                            <constraint firstItem="3jf-HN-lVz" firstAttribute="leading" secondItem="Ge5-4i-c4F" secondAttribute="leading" id="QvQ-Gp-N6r"/>
                            <constraint firstItem="a3I-lb-Ai6" firstAttribute="top" secondItem="3jf-HN-lVz" secondAttribute="bottom" id="Ue0-UH-kxe"/>
                            <constraint firstItem="3jf-HN-lVz" firstAttribute="top" secondItem="0OC-Vl-SlB" secondAttribute="top" id="eb9-Zh-dmo"/>
                        </constraints>
                        <variation key="default">
                            <mask key="constraints">
                                <exclude reference="49U-xF-EQh"/>
                                <exclude reference="Kog-8l-OhD"/>
                                <exclude reference="OXD-GG-H1V"/>
                                <exclude reference="B88-h4-23t"/>
                            </mask>
                        </variation>
                    </view>
                    <connections>
                        <outlet property="peersLabel" destination="HhI-Ni-8J8" id="lJD-gK-S5n"/>
                        <outlet property="progressLabel" destination="Dyu-uI-e3s" id="11L-g5-Xlz"/>
                        <outlet property="progressView" destination="iQF-mn-H34" id="yxl-Nj-8wf"/>
                        <outlet property="seedsLabel" destination="odl-qX-n2O" id="fNP-Rd-afo"/>
                        <outlet property="speedLabel" destination="ZtX-Eh-3Ck" id="zu4-Oy-HuH"/>
                        <outlet property="statusLabel" destination="4bR-E2-MXi" id="Omi-rU-Gma"/>
                        <outlet property="titleLabel" destination="BFA-o4-k8D" id="H8g-9M-v8E"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="tWv-oB-zv8" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="166" y="1127"/>
        </scene>
        <!--Movies View Controller-->
        <scene sceneID="w8j-0J-Eiu">
            <objects>
                <viewController id="MfG-VV-Dsq" customClass="MoviesViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="7zu-Fk-ucI"/>
                        <viewControllerLayoutGuide type="bottom" id="am9-41-5Cg"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="DTT-77-bFA">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="un7-QQ-yb5">
                                <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="dLT-p7-0kC">
                                    <size key="itemSize" width="50" height="50"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells/>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="un7-QQ-yb5" secondAttribute="trailing" id="LMg-Wo-DNY"/>
                            <constraint firstAttribute="bottom" secondItem="un7-QQ-yb5" secondAttribute="bottom" id="MtX-vN-2gj"/>
                            <constraint firstItem="am9-41-5Cg" firstAttribute="top" secondItem="un7-QQ-yb5" secondAttribute="bottom" id="P8d-Zl-9ZP"/>
                            <constraint firstItem="un7-QQ-yb5" firstAttribute="leading" secondItem="DTT-77-bFA" secondAttribute="leading" id="cFz-Pk-Mmz"/>
                            <constraint firstItem="un7-QQ-yb5" firstAttribute="top" secondItem="DTT-77-bFA" secondAttribute="topMargin" id="eya-tL-5GQ"/>
                        </constraints>
                        <variation key="default">
                            <mask key="constraints">
                                <exclude reference="P8d-Zl-9ZP"/>
                            </mask>
                        </variation>
                    </view>
                    <navigationItem key="navigationItem" id="emw-Gq-25X"/>
                    <connections>
                        <outlet property="collectionView" destination="un7-QQ-yb5" id="WCU-nz-hXB"/>
                        <outlet property="collectionViewLayout" destination="dLT-p7-0kC" id="miO-uc-V55"/>
                        <segue destination="2vz-Nk-i3O" kind="show" identifier="showDetails" id="md6-Ka-eFz"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="s9J-gI-5Xf" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1854" y="1127"/>
        </scene>
        <!--Movies-->
        <scene sceneID="MVY-tk-2U8">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="laf-Ml-R54" sceneMemberID="viewController">
                    <tabBarItem key="tabBarItem" title="Movies" image="MoviesIcon" id="hdd-ic-XlJ"/>
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" id="jlQ-Ip-DcT">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="MfG-VV-Dsq" kind="relationship" relationship="rootViewController" id="ZdR-AN-H6V"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="EPu-48-ilK" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1009" y="1127"/>
        </scene>
        <!--Show Details View Controller-->
        <scene sceneID="jc0-r0-ie0">
            <objects>
                <viewController id="6yf-Ps-CJA" customClass="ShowDetailsViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Kkk-Uf-QOx"/>
                        <viewControllerLayoutGuide type="bottom" id="Gxb-eF-kn7"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="fSO-ml-ygC">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="Cix-TO-yDb">
                                <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="QOJ-dh-oMS" customClass="StratchyHeaderLayout" customModule="PopcornTime" customModuleProvider="target">
                                    <size key="itemSize" width="50" height="50"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="5" minY="15" maxX="5" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells>
                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="EpisodeCell" id="WYM-12-06H">
                                        <rect key="frame" x="5" y="79" width="50" height="50"/>
                                        <autoresizingMask key="autoresizingMask"/>
                                        <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                            <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                                        </view>
                                        <color key="backgroundColor" red="1" green="0.60942627989999998" blue="0.53172264930000002" alpha="1" colorSpace="calibratedRGB"/>
                                    </collectionViewCell>
                                </cells>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="Cix-TO-yDb" secondAttribute="trailing" id="1Ke-bE-sbv"/>
                            <constraint firstItem="Cix-TO-yDb" firstAttribute="top" secondItem="fSO-ml-ygC" secondAttribute="topMargin" id="Fg7-jg-DlH"/>
                            <constraint firstItem="Cix-TO-yDb" firstAttribute="leading" secondItem="fSO-ml-ygC" secondAttribute="leading" id="Gbz-4s-5ox"/>
                            <constraint firstItem="Cix-TO-yDb" firstAttribute="bottom" secondItem="fSO-ml-ygC" secondAttribute="bottomMargin" id="uhG-Ot-HZh"/>
                        </constraints>
                    </view>
                    <connections>
                        <outlet property="collectionView" destination="Cix-TO-yDb" id="YUl-P7-ImU"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="5nP-va-hCS" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2650" y="-662"/>
        </scene>
        <!--Movie Details View Controller-->
        <scene sceneID="CbQ-5W-veU">
            <objects>
                <viewController id="2vz-Nk-i3O" customClass="MovieDetailsViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="Cp9-yw-pA3"/>
                        <viewControllerLayoutGuide type="bottom" id="3zw-Wx-sxv"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="Ybe-E9-ZTf">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="FOJ-U6-lFA">
                                <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="dvR-y0-Sip" customClass="StratchyHeaderLayout" customModule="PopcornTime" customModuleProvider="target">
                                    <size key="itemSize" width="50" height="50"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="5" minY="15" maxX="5" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells>
                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="EpisodeCell" id="8rK-gB-HyN">
                                        <rect key="frame" x="5" y="79" width="50" height="50"/>
                                        <autoresizingMask key="autoresizingMask"/>
                                        <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                            <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                                        </view>
                                        <color key="backgroundColor" red="1" green="0.60942627989999998" blue="0.53172264930000002" alpha="1" colorSpace="calibratedRGB"/>
                                    </collectionViewCell>
                                </cells>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="FOJ-U6-lFA" firstAttribute="top" secondItem="Cp9-yw-pA3" secondAttribute="bottom" id="Imy-I5-tBP"/>
                            <constraint firstItem="FOJ-U6-lFA" firstAttribute="top" secondItem="Ybe-E9-ZTf" secondAttribute="topMargin" id="MU0-Fg-HLk"/>
                            <constraint firstAttribute="bottom" secondItem="FOJ-U6-lFA" secondAttribute="bottom" id="gRn-c0-JpL"/>
                            <constraint firstAttribute="trailing" secondItem="FOJ-U6-lFA" secondAttribute="trailing" id="n2p-fc-1bd"/>
                            <constraint firstItem="FOJ-U6-lFA" firstAttribute="leading" secondItem="Ybe-E9-ZTf" secondAttribute="leading" id="xGL-To-8Fe"/>
                        </constraints>
                        <variation key="default">
                            <mask key="constraints">
                                <exclude reference="Imy-I5-tBP"/>
                            </mask>
                        </variation>
                    </view>
                    <connections>
                        <outlet property="collectionView" destination="FOJ-U6-lFA" id="nbx-ij-BiF"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="hi7-OG-RrF" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2650" y="1127"/>
        </scene>
        <!--Settings-->
        <scene sceneID="bem-lN-RrM">
            <objects>
                <viewController id="PsM-1R-DZR" customClass="SettingsViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="DZI-mU-Mb1"/>
                        <viewControllerLayoutGuide type="bottom" id="EN2-Q0-mCJ"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="f1e-yA-mmT">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" translatesAutoresizingMaskIntoConstraints="NO" id="09A-zd-jWh">
                                <rect key="frame" x="0.0" y="0.0" width="600" height="556"/>
                                <color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
                                <connections>
                                    <outlet property="dataSource" destination="PsM-1R-DZR" id="LkZ-4H-AMh"/>
                                    <outlet property="delegate" destination="PsM-1R-DZR" id="hXZ-yB-VQR"/>
                                </connections>
                            </tableView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="09A-zd-jWh" firstAttribute="bottom" secondItem="EN2-Q0-mCJ" secondAttribute="top" id="98Q-Ut-SCA"/>
                            <constraint firstAttribute="trailing" secondItem="09A-zd-jWh" secondAttribute="trailing" id="XWT-CL-eDQ"/>
                            <constraint firstItem="09A-zd-jWh" firstAttribute="leading" secondItem="f1e-yA-mmT" secondAttribute="leading" id="o1a-Ap-OIw"/>
                            <constraint firstItem="09A-zd-jWh" firstAttribute="top" secondItem="f1e-yA-mmT" secondAttribute="top" id="wC8-xJ-bK0"/>
                        </constraints>
                    </view>
                    <toolbarItems/>
                    <navigationItem key="navigationItem" title="Settings" id="yNe-p8-SDg">
                        <barButtonItem key="leftBarButtonItem" title="Done" id="9er-hO-ljh">
                            <connections>
                                <action selector="doneButtonTapped:" destination="PsM-1R-DZR" id="hyK-bZ-4Cs"/>
                            </connections>
                        </barButtonItem>
                    </navigationItem>
                    <simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="c2O-RD-Dnk" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2642" y="-2339"/>
        </scene>
        <!--Favorites-->
        <scene sceneID="Ajz-ma-oZc">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="ZTe-Ju-nKb" sceneMemberID="viewController">
                    <tabBarItem key="tabBarItem" title="Favorites" image="FavoritesIcon" id="fW6-S6-lRJ"/>
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" id="vNU-OG-5CV">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="UYG-Ri-Xwt" kind="relationship" relationship="rootViewController" id="d95-MP-Deg"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="bPA-j1-sYU" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1009" y="-1583"/>
        </scene>
        <!--Favorites View Controller-->
        <scene sceneID="295-pu-uhc">
            <objects>
                <viewController id="UYG-Ri-Xwt" customClass="FavoritesViewController" customModule="PopcornTime" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="63E-PP-ohP"/>
                        <viewControllerLayoutGuide type="bottom" id="IpR-5f-yWF"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="M3M-4W-n7v">
                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="eI5-vY-Geb">
                                <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="wc9-WL-RHv">
                                    <size key="itemSize" width="50" height="50"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells/>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="eI5-vY-Geb" firstAttribute="leading" secondItem="M3M-4W-n7v" secondAttribute="leading" id="Gcb-tq-ZVc"/>
                            <constraint firstAttribute="trailing" secondItem="eI5-vY-Geb" secondAttribute="trailing" id="Ltt-Ro-FiQ"/>
                            <constraint firstItem="eI5-vY-Geb" firstAttribute="top" secondItem="M3M-4W-n7v" secondAttribute="top" id="gg3-bx-fnL"/>
                            <constraint firstAttribute="bottom" secondItem="eI5-vY-Geb" secondAttribute="bottom" id="hoL-CT-C9N"/>
                        </constraints>
                    </view>
                    <navigationItem key="navigationItem" id="MY5-kk-pyb">
                        <barButtonItem key="leftBarButtonItem" image="SettingsIcon" id="b18-US-aYw">
                            <connections>
                                <segue destination="laO-YO-bEr" kind="presentation" modalPresentationStyle="formSheet" id="MHB-oZ-cjC"/>
                            </connections>
                        </barButtonItem>
                    </navigationItem>
                    <connections>
                        <outlet property="collectionView" destination="eI5-vY-Geb" id="9bl-Ru-8eV"/>
                        <outlet property="collectionViewLayout" destination="wc9-WL-RHv" id="heF-Dp-lKu"/>
                        <segue destination="6yf-Ps-CJA" kind="show" identifier="showDetailsForFavoriteShow" id="yKj-Tm-VOw"/>
                        <segue destination="nkV-Ie-GtD" kind="show" identifier="showDetailsForFavoriteAnime" id="Qrp-vN-Wm3"/>
                        <segue destination="2vz-Nk-i3O" kind="show" identifier="showDetailsForFavoriteMovie" id="Wdb-6o-Fxi"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="OKd-O3-qVh" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1854" y="-1583"/>
        </scene>
        <!--Navigation Controller-->
        <scene sceneID="umC-OZ-DUF">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="laO-YO-bEr" sceneMemberID="viewController">
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" id="mhs-Pw-TcL">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="PsM-1R-DZR" kind="relationship" relationship="rootViewController" id="Hga-lw-gLH"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="pJk-EZ-fTT" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1854" y="-2355"/>
        </scene>
    </scenes>
    <resources>
        <image name="AnimeIcon" width="30" height="30"/>
        <image name="FavoritesIcon" width="30" height="30"/>
        <image name="MoviesIcon" width="30" height="30"/>
        <image name="SettingsIcon" width="30" height="30"/>
        <image name="ShowsIcon" width="30" height="30"/>
    </resources>
    <inferredMetricsTieBreakers>
        <segue reference="Qrp-vN-Wm3"/>
        <segue reference="yKj-Tm-VOw"/>
        <segue reference="Wdb-6o-Fxi"/>
    </inferredMetricsTieBreakers>
</document>


================================================
FILE: PopcornTime/Views/EpisodeCell.swift
================================================
//
//  EpisodeCell.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/13/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class EpisodeCell: UICollectionViewCell {
  
  let watchedAlpha:CGFloat = 0.5
  let defaultAlpha:CGFloat = 1.0
    
    @IBOutlet weak var titleLabel: UILabel!
    var watchedEpisode = false {
      didSet {
        if watchedEpisode {
          alpha = watchedAlpha
        } else {
          alpha = defaultAlpha
        }
      }
    }
}


================================================
FILE: PopcornTime/Views/EpisodeCell.xib
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="15A178w" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="EpisodeCell" id="gTV-IL-0wX" customClass="EpisodeCell" customModule="PopcornTime" customModuleProvider="target">
            <rect key="frame" x="0.0" y="0.0" width="381" height="86"/>
            <autoresizingMask key="autoresizingMask"/>
            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                <rect key="frame" x="0.0" y="0.0" width="381" height="86"/>
                <subviews>
                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hac-x6-d8V">
                        <rect key="frame" x="0.0" y="0.0" width="381" height="86"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rw3-FD-IDF">
                                <rect key="frame" x="8" y="33" width="365" height="20"/>
                                <animations/>
                                <fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
                                <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <animations/>
                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstAttribute="trailingMargin" secondItem="rw3-FD-IDF" secondAttribute="trailing" id="4JM-g6-1yg"/>
                            <constraint firstAttribute="centerY" secondItem="rw3-FD-IDF" secondAttribute="centerY" id="Xme-ZK-Q6S"/>
                            <constraint firstItem="rw3-FD-IDF" firstAttribute="leading" secondItem="hac-x6-d8V" secondAttribute="leadingMargin" id="m7b-qe-tLL"/>
                        </constraints>
                    </view>
                </subviews>
                <animations/>
                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
            </view>
            <animations/>
            <color key="backgroundColor" red="0.29803922772407532" green="0.29803922772407532" blue="0.29803922772407532" alpha="0.45000000000000001" colorSpace="calibratedRGB"/>
            <constraints>
                <constraint firstAttribute="trailing" secondItem="hac-x6-d8V" secondAttribute="trailing" id="3tn-e1-whc"/>
                <constraint firstItem="hac-x6-d8V" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="ZQU-6d-HeS"/>
                <constraint firstItem="hac-x6-d8V" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="cVo-K4-VEE"/>
                <constraint firstAttribute="bottom" secondItem="hac-x6-d8V" secondAttribute="bottom" id="ief-JJ-Ktm"/>
            </constraints>
            <size key="customSize" width="381" height="86"/>
            <connections>
                <outlet property="titleLabel" destination="rw3-FD-IDF" id="8M1-8P-KLo"/>
            </connections>
            <point key="canvasLocation" x="340.5" y="236"/>
        </collectionViewCell>
    </objects>
</document>


================================================
FILE: PopcornTime/Views/MoreShowsCollectionViewCell.swift
================================================
//
//  MoreShowsCollectionViewCell.swift
//  PopcornTime
//
//  Created by Andrew  K. on 3/10/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class MoreShowsCollectionViewCell: UICollectionViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

}


================================================
FILE: PopcornTime/Views/MoreShowsCollectionViewCell.xib
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="MoreShowsCell" id="gTV-IL-0wX" customClass="MoreShowsCollectionViewCell" customModule="PopcornTime" customModuleProvider="target">
            <rect key="frame" x="0.0" y="0.0" width="228" height="254"/>
            <autoresizingMask key="autoresizingMask"/>
            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                <rect key="frame" x="0.0" y="0.0" width="228" height="254"/>
                <subviews>
                    <activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="Iyp-NF-gbb">
                        <rect key="frame" x="96" y="108" width="37" height="37"/>
                    </activityIndicatorView>
                </subviews>
                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
            </view>
            <constraints>
                <constraint firstAttribute="centerY" secondItem="Iyp-NF-gbb" secondAttribute="centerY" id="LVh-dH-GmR"/>
                <constraint firstAttribute="centerX" secondItem="Iyp-NF-gbb" secondAttribute="centerX" id="QL8-3z-U1F"/>
            </constraints>
            <size key="customSize" width="228" height="254"/>
            <point key="canvasLocation" x="232" y="359"/>
        </collectionViewCell>
    </objects>
</document>


================================================
FILE: PopcornTime/Views/SeasonHeader.swift
================================================
//
//  SeasonHeader.swift
//  PopcornTime
//
//  Created by Andrew  K. on 4/14/15.
//  Copyright (c) 2015 PopcornTime. All rights reserved.
//

import UIKit

class SeasonHeader: UICollectionReusableView {

    @IBOutlet weak var container: UIView!
    @IBOutlet weak var titleLabel: UILabel!
    
}


================================================
FILE: PopcornTime/Views/SeasonHeader.xib
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="U6b-Vx-4bR" customClass="SeasonHeader" customModule="PopcornTime" customModuleProvider="target">
            <rect key="frame" x="0.0" y="0.0" width="320" height="50"/>
            <autoresizingMask key="autoresizingMask"/>
            <subviews>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bkC-4d-qdf" userLabel="container">
                    <rect key="frame" x="0.0" y="0.0" width="320" height="50"/>
                    <subviews>
                 
Download .txt
gitextract_6kv41eo_/

├── .gitignore
├── Podfile
├── PopcornTime/
│   ├── Controllers/
│   │   ├── AnimeDetailsViewController.swift
│   │   ├── AnimeViewController.swift
│   │   ├── BarHidingViewController.swift
│   │   ├── BaseCollectionViewController.swift
│   │   ├── BaseDetailsViewController.swift
│   │   ├── ColorfullTabBarController.swift
│   │   ├── FavoritesViewController.swift
│   │   ├── LoadingViewController.swift
│   │   ├── MovieDetailsViewController.swift
│   │   ├── MoviesViewController.swift
│   │   ├── OAuthViewController.swift
│   │   ├── PagedViewController.swift
│   │   ├── ParseViewController.swift
│   │   ├── SettingsViewController.swift
│   │   ├── ShowDetailsViewController.swift
│   │   └── ShowsViewController.swift
│   ├── Info.plist
│   ├── Models/
│   │   ├── APIManager.swift
│   │   ├── Anime.swift
│   │   ├── AppDelegate.swift
│   │   ├── BaseStructures.swift
│   │   ├── BasicInfo.swift
│   │   ├── DataManager.swift
│   │   ├── Extensions.swift
│   │   ├── Image.swift
│   │   ├── ImageProvider.swift
│   │   ├── Movie.swift
│   │   ├── PTAPIManager.h
│   │   ├── PTAPIManager.m
│   │   ├── PTTorrentStreamer.h
│   │   ├── PTTorrentStreamer.mm
│   │   ├── ParseManager.swift
│   │   └── Show.swift
│   ├── PopcornTime-Bridging-Header.h
│   ├── Resources/
│   │   ├── Images.xcassets/
│   │   │   ├── AnimeIcon.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   ├── BigLogo.imageset/
│   │   │   │   └── Contents.json
│   │   │   ├── Contents.json
│   │   │   └── SubwayIconSet/
│   │   │       ├── AddToFavoritesIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       ├── FavoritesIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       ├── MoviesIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       ├── RemoveFromFavoritesIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       ├── SettingsIcon.imageset/
│   │   │       │   └── Contents.json
│   │   │       └── ShowsIcon.imageset/
│   │   │           └── Contents.json
│   │   ├── Launch Screen.xib
│   │   └── Main.storyboard
│   └── Views/
│       ├── EpisodeCell.swift
│       ├── EpisodeCell.xib
│       ├── MoreShowsCollectionViewCell.swift
│       ├── MoreShowsCollectionViewCell.xib
│       ├── SeasonHeader.swift
│       ├── SeasonHeader.xib
│       ├── ShowCollectionViewCell.swift
│       ├── ShowCollectionViewCell.xib
│       ├── StratchyHeader.swift
│       ├── StratchyHeader.xib
│       └── StratchyHeaderLayout.swift
├── PopcornTime.xcodeproj/
│   ├── project.pbxproj
│   └── xcshareddata/
│       └── xcschemes/
│           └── PopcornTime.xcscheme
├── README.md
├── Thirdparties/
│   └── VLCKit/
│       └── Dropin-Player/
│           ├── VDLPlaybackViewController.h
│           ├── VDLPlaybackViewController.m
│           └── VDLPlaybackViewController.xib
└── popcorntime_api.paw
Download .txt
SYMBOL INDEX (2 symbols across 2 files)

FILE: PopcornTime/Models/PTAPIManager.h
  type PTItemTypeMovie (line 16) | typedef NS_ENUM(NSInteger, PTItemType) {

FILE: PopcornTime/Models/PTTorrentStreamer.h
  type PTTorrentStatus (line 11) | typedef struct {
Condensed preview — 66 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (390K chars).
[
  {
    "path": ".gitignore",
    "chars": 1067,
    "preview": "# Created by https://www.gitignore.io\n\n### OSX ###\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n"
  },
  {
    "path": "Podfile",
    "chars": 435,
    "preview": "# Uncomment this line to define a global platform for your project\n# platform :ios, '8.0'\ninhibit_all_warnings!\n\nsource "
  },
  {
    "path": "PopcornTime/Controllers/AnimeDetailsViewController.swift",
    "chars": 2003,
    "preview": "//\n//  ShowDetailsViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/13/15.\n//  Copyright (c) 2015 P"
  },
  {
    "path": "PopcornTime/Controllers/AnimeViewController.swift",
    "chars": 1730,
    "preview": "//\n//  MoviesViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/15/15.\n//  Copyright (c) 2015 Popcor"
  },
  {
    "path": "PopcornTime/Controllers/BarHidingViewController.swift",
    "chars": 921,
    "preview": "//\n//  BarHidingViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/13/15.\n//  Copyright (c) 2015 Pop"
  },
  {
    "path": "PopcornTime/Controllers/BaseCollectionViewController.swift",
    "chars": 6513,
    "preview": "//\n//  ShowsCollectionViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/8/15.\n//  Copyright (c) 201"
  },
  {
    "path": "PopcornTime/Controllers/BaseDetailsViewController.swift",
    "chars": 13139,
    "preview": "//\n//  BaseDetailsViewController.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/21/15.\n//  Copyright (c) "
  },
  {
    "path": "PopcornTime/Controllers/ColorfullTabBarController.swift",
    "chars": 1757,
    "preview": "//\n//  ColorfullTabBarController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 4/10/15.\n//  Copyright (c) 2015 P"
  },
  {
    "path": "PopcornTime/Controllers/FavoritesViewController.swift",
    "chars": 2493,
    "preview": "//\n//  FavoritesViewController.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/13/15.\n//  Copyright (c) 20"
  },
  {
    "path": "PopcornTime/Controllers/LoadingViewController.swift",
    "chars": 2473,
    "preview": "//\n//  LoadingViewController.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/15/15.\n//  Copyright (c) 2015"
  },
  {
    "path": "PopcornTime/Controllers/MovieDetailsViewController.swift",
    "chars": 1988,
    "preview": "//\n//  ShowDetailsViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/13/15.\n//  Copyright (c) 2015 P"
  },
  {
    "path": "PopcornTime/Controllers/MoviesViewController.swift",
    "chars": 1777,
    "preview": "//\n//  MoviesViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/19/15.\n//  Copyright (c) 2015 Popcor"
  },
  {
    "path": "PopcornTime/Controllers/OAuthViewController.swift",
    "chars": 2091,
    "preview": "//\n//  WebViewController.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/15/15.\n//  Copyright (c) 2015 Pop"
  },
  {
    "path": "PopcornTime/Controllers/PagedViewController.swift",
    "chars": 6690,
    "preview": "//\n//  PagedViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/19/15.\n//  Copyright (c) 2015 Popcorn"
  },
  {
    "path": "PopcornTime/Controllers/ParseViewController.swift",
    "chars": 1822,
    "preview": "//\n//  ParseViewController.swift\n//\n//\n//  Created by Andriy K. on 6/22/15.\n//\n//\n\nimport UIKit\n\nclass ParseViewControll"
  },
  {
    "path": "PopcornTime/Controllers/SettingsViewController.swift",
    "chars": 2321,
    "preview": "//\n//  SettingsViewController.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 4/4/15.\n//  Copyright (c) 2015"
  },
  {
    "path": "PopcornTime/Controllers/ShowDetailsViewController.swift",
    "chars": 2179,
    "preview": "//\n//  ShowDetailsViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/13/15.\n//  Copyright (c) 2015 P"
  },
  {
    "path": "PopcornTime/Controllers/ShowsViewController.swift",
    "chars": 1745,
    "preview": "//\n//  TVSeriesShowsViewController.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/9/15.\n//  Copyright (c) 2015 "
  },
  {
    "path": "PopcornTime/Info.plist",
    "chars": 1746,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "PopcornTime/Models/APIManager.swift",
    "chars": 5323,
    "preview": "//\n//  APIManager.swift\n//  popcornTime\n//\n//  Created by Danylo Kostyshyn on 3/13/15.\n//  Copyright (c) 2015 Danylo Kos"
  },
  {
    "path": "PopcornTime/Models/Anime.swift",
    "chars": 4194,
    "preview": "//\n//  Anime.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/19/15.\n//  Copyright (c) 2015 PopcornTime. Al"
  },
  {
    "path": "PopcornTime/Models/AppDelegate.swift",
    "chars": 557,
    "preview": "//\n//  AppDelegate.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/13/15.\n//  Copyright (c) 2015 PopcornTi"
  },
  {
    "path": "PopcornTime/Models/BaseStructures.swift",
    "chars": 525,
    "preview": "//\n//  Video.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/21/15.\n//  Copyright (c) 2015 PopcornTime. Al"
  },
  {
    "path": "PopcornTime/Models/BasicInfo.swift",
    "chars": 2382,
    "preview": "//\n//  BasicInfo.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/19/15.\n//  Copyright (c) 2015 PopcornTime"
  },
  {
    "path": "PopcornTime/Models/DataManager.swift",
    "chars": 2822,
    "preview": "//\n//  DataManager.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/24/15.\n//  Copyright (c) 2015 PopcornTi"
  },
  {
    "path": "PopcornTime/Models/Extensions.swift",
    "chars": 422,
    "preview": "//\n//  UIImage+PopcornTime.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/30/15.\n//  Copyright (c) 2015 P"
  },
  {
    "path": "PopcornTime/Models/Image.swift",
    "chars": 1053,
    "preview": "//\n//  File.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/21/15.\n//  Copyright (c) 2015 PopcornTime. All"
  },
  {
    "path": "PopcornTime/Models/ImageProvider.swift",
    "chars": 785,
    "preview": "//\n//  ImageProvider.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/10/15.\n//  Copyright (c) 2015 PopcornTime. "
  },
  {
    "path": "PopcornTime/Models/Movie.swift",
    "chars": 1868,
    "preview": "//\n//  Movie.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/19/15.\n//  Copyright (c) 2015 PopcornTime. Al"
  },
  {
    "path": "PopcornTime/Models/PTAPIManager.h",
    "chars": 1719,
    "preview": "//\n//  PTAPIManager.h\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 2/25/15.\n//  Copyright (c) 2015 PopcornTime."
  },
  {
    "path": "PopcornTime/Models/PTAPIManager.m",
    "chars": 16049,
    "preview": "//\n//  PTAPIManager.m\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 2/25/15.\n//  Copyright (c) 2015 PopcornTime."
  },
  {
    "path": "PopcornTime/Models/PTTorrentStreamer.h",
    "chars": 969,
    "preview": "//\n//  PTTorrentStreamer.h\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 2/23/15.\n//  Copyright (c) 2015 Popcorn"
  },
  {
    "path": "PopcornTime/Models/PTTorrentStreamer.mm",
    "chars": 13481,
    "preview": "//\n//  PTTorrentStreamer.m\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 2/23/15.\n//  Copyright (c) 2015 Popcorn"
  },
  {
    "path": "PopcornTime/Models/ParseManager.swift",
    "chars": 8857,
    "preview": "//\n//  ParseManager.swift\n//  \n//\n//  Created by Andriy K. on 6/23/15.\n//\n//\n\nimport UIKit\n\nclass ParseShowData: NSObjec"
  },
  {
    "path": "PopcornTime/Models/Show.swift",
    "chars": 4595,
    "preview": "//\n//  Show.swift\n//  PopcornTime\n//\n//  Created by Danylo Kostyshyn on 3/19/15.\n//  Copyright (c) 2015 PopcornTime. All"
  },
  {
    "path": "PopcornTime/PopcornTime-Bridging-Header.h",
    "chars": 325,
    "preview": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n\n#import \"PTAPIMa"
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/AnimeIcon.imageset/Contents.json",
    "chars": 302,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n     "
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 1609,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\""
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/BigLogo.imageset/Contents.json",
    "chars": 314,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n     "
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/SubwayIconSet/AddToFavoritesIcon.imageset/Contents.json",
    "chars": 308,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n     "
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/SubwayIconSet/FavoritesIcon.imageset/Contents.json",
    "chars": 308,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n     "
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/SubwayIconSet/MoviesIcon.imageset/Contents.json",
    "chars": 309,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n     "
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/SubwayIconSet/RemoveFromFavoritesIcon.imageset/Contents.json",
    "chars": 308,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n     "
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/SubwayIconSet/SettingsIcon.imageset/Contents.json",
    "chars": 309,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n     "
  },
  {
    "path": "PopcornTime/Resources/Images.xcassets/SubwayIconSet/ShowsIcon.imageset/Contents.json",
    "chars": 309,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n     "
  },
  {
    "path": "PopcornTime/Resources/Launch Screen.xib",
    "chars": 3621,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" versi"
  },
  {
    "path": "PopcornTime/Resources/Main.storyboard",
    "chars": 54116,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "PopcornTime/Views/EpisodeCell.swift",
    "chars": 498,
    "preview": "//\n//  EpisodeCell.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/13/15.\n//  Copyright (c) 2015 PopcornTime. Al"
  },
  {
    "path": "PopcornTime/Views/EpisodeCell.xib",
    "chars": 4291,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" versi"
  },
  {
    "path": "PopcornTime/Views/MoreShowsCollectionViewCell.swift",
    "chars": 336,
    "preview": "//\n//  MoreShowsCollectionViewCell.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/10/15.\n//  Copyright (c) 2015"
  },
  {
    "path": "PopcornTime/Views/MoreShowsCollectionViewCell.xib",
    "chars": 2209,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" versi"
  },
  {
    "path": "PopcornTime/Views/SeasonHeader.swift",
    "chars": 299,
    "preview": "//\n//  SeasonHeader.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 4/14/15.\n//  Copyright (c) 2015 PopcornTime. A"
  },
  {
    "path": "PopcornTime/Views/SeasonHeader.xib",
    "chars": 3871,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" versi"
  },
  {
    "path": "PopcornTime/Views/ShowCollectionViewCell.swift",
    "chars": 710,
    "preview": "//\n//  ShowCollectionViewCell.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/8/15.\n//  Copyright (c) 2015 Popco"
  },
  {
    "path": "PopcornTime/Views/ShowCollectionViewCell.xib",
    "chars": 6891,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" versi"
  },
  {
    "path": "PopcornTime/Views/StratchyHeader.swift",
    "chars": 3205,
    "preview": "//\n//  StratchyHeader.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 4/6/15.\n//  Copyright (c) 2015 PopcornTime. "
  },
  {
    "path": "PopcornTime/Views/StratchyHeader.xib",
    "chars": 16946,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" versi"
  },
  {
    "path": "PopcornTime/Views/StratchyHeaderLayout.swift",
    "chars": 3565,
    "preview": "//\n//  StratchyHeaderLayout.swift\n//  PopcornTime\n//\n//  Created by Andrew  K. on 3/13/15.\n//  Copyright (c) 2015 Popcor"
  },
  {
    "path": "PopcornTime.xcodeproj/project.pbxproj",
    "chars": 47349,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "PopcornTime.xcodeproj/xcshareddata/xcschemes/PopcornTime.xcscheme",
    "chars": 3351,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0820\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "README.md",
    "chars": 866,
    "preview": "## PopcornTime for iOS\n\n[![Build Status](https://www.bitrise.io/app/9ee06c0598c7cbdb.svg?token=nH-7MkkoZ7EpSlvMce4KkA)]("
  },
  {
    "path": "Thirdparties/VLCKit/Dropin-Player/VDLPlaybackViewController.h",
    "chars": 2746,
    "preview": "/* Copyright (c) 2013, Felix Paul Kühne and VideoLAN\n * All rights reserved.\n *\n * Redistribution and use in source and "
  },
  {
    "path": "Thirdparties/VLCKit/Dropin-Player/VDLPlaybackViewController.m",
    "chars": 12829,
    "preview": "/* Copyright (c) 2013, Felix Paul Kühne and VideoLAN\n * All rights reserved.\n *\n * Redistribution and use in source and "
  },
  {
    "path": "Thirdparties/VLCKit/Dropin-Player/VDLPlaybackViewController.xib",
    "chars": 34012,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<archive type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"8.00\">\n\t<data"
  },
  {
    "path": "popcorntime_api.paw",
    "chars": 33852,
    "preview": "<?xml version=\"1.0\" standalone=\"no\"?>\n<!DOCTYPE database SYSTEM \"file:///System/Library/DTDs/CoreData.dtd\">\n\n<database>\n"
  }
]

About this extraction

This page contains the full source code of the danylokostyshyn/popcorntime-ios GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 66 files (352.1 KB), approximately 93.3k tokens, and a symbol index with 2 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!