<commit_before>import UIKit

@objc(WMFArticleCollectionViewControllerDelegate)
protocol ArticleCollectionViewControllerDelegate: NSObjectProtocol {
    func articleCollectionViewController(_ articleCollectionViewController: ArticleCollectionViewController, didSelectArticleWithURL: URL, at indexPath: IndexPath)
}

@objc(WMFArticleCollectionViewController)
class ArticleCollectionViewController: ColumnarCollectionViewController, ReadingListHintPresenter, EditableCollection, EventLoggingEventValuesProviding {
    @objc var dataStore: MWKDataStore! {
        didSet {
            readingListHintController = ReadingListHintController(dataStore: dataStore, presenter: self)
        }
    }
    var cellLayoutEstimate: ColumnarCollectionViewLayoutHeightEstimate?

    var editController: CollectionViewEditController!
    var readingListHintController: ReadingListHintController?
    
    @objc weak var delegate: ArticleCollectionViewControllerDelegate?

    var feedFunnelContext: FeedFunnelContext?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        layoutManager.register(ArticleRightAlignedImageCollectionViewCell.self, forCellWithReuseIdentifier: ArticleRightAlignedImageCollectionViewCell.identifier, addPlaceholder: true)
        setupEditController()
    }
    
    open func configure(cell: ArticleRightAlignedImageCollectionViewCell, forItemAt indexPath: IndexPath, layoutOnly: Bool) {
        guard let article = article(at: indexPath) else {
            return
        }
        cell.configure(article: article, displayType: .compactList, index: indexPath.item, shouldShowSeparators: true, theme: theme, layoutOnly: layoutOnly)
        cell.topSeparator.isHidden = indexPath.item == 0
        cell.bottomSeparator.isHidden = indexPath.item == self.collectionView(collectionView, numberOfItemsInSection: indexPath.section) - 1
        cell.layoutMargins = layout.itemLayoutMargins
        editController.configureSwipeableCell(cell, forItemAt: indexPath, layoutOnly: layoutOnly)
    }
    
    open func articleURL(at indexPath: IndexPath) -> URL? {
        assert(false, "Subclassers should override this function")
        return nil
    }
    
    open func imageURL(at indexPath: IndexPath) -> URL? {
        guard let article = article(at: indexPath) else {
            return nil
        }
        return article.imageURL(forWidth: traitCollection.wmf_nearbyThumbnailWidth)
    }
    
    override func imageURLsForItemAt(_ indexPath: IndexPath) -> Set<URL>? {
        guard let imageURL = imageURL(at: indexPath) else {
            return nil
        }
        return [imageURL]
    }
    
    open func article(at indexPath: IndexPath) -> WMFArticle? {
        assert(false, "Subclassers should override this function")
        return nil
    }
    
    open func delete(at indexPath: IndexPath) {
        assert(false, "Subclassers should override this function")
    }
    
    open func canDelete(at indexPath: IndexPath) -> Bool {
        return false
    }
    
    open func canSave(at indexPath: IndexPath) -> Bool {
        guard let articleURL = articleURL(at: indexPath) else {
            return false
        }
        return !dataStore.savedPageList.isSaved(articleURL)
    }
    
    open func canUnsave(at indexPath: IndexPath) -> Bool {
        guard let articleURL = articleURL(at: indexPath) else {
            return false
        }
        return dataStore.savedPageList.isSaved(articleURL)
    }
    
    open func canShare(at indexPath: IndexPath) -> Bool {
        return articleURL(at: indexPath) != nil
    }
    
    override func contentSizeCategoryDidChange(_ notification: Notification?) {
        cellLayoutEstimate = nil
        super.contentSizeCategoryDidChange(notification)
    }
    
    // MARK: - EventLoggingEventValuesProviding
    
    var eventLoggingCategory: EventLoggingCategory {
        assertionFailure("Subclassers should override this property")
        return .unknown
    }
    
    var eventLoggingLabel: EventLoggingLabel? {
        return nil
    }

    var eventLoggingIndex: NSNumber? {
        guard let index = previewedIndexPath?.item else {
            return nil
        }
        return NSNumber(value: index)
    }

    var previewedIndexPath: IndexPath?

    // MARK: - Layout
    
    override func collectionView(_ collectionView: UICollectionView, estimatedHeightForItemAt indexPath: IndexPath, forColumnWidth columnWidth: CGFloat) -> ColumnarCollectionViewLayoutHeightEstimate {
        // The layout estimate can be re-used in this case becuause both labels are one line, meaning the cell
        // size only varies with font size. The layout estimate is nil'd when the font size changes on trait collection change
        if let estimate = cellLayoutEstimate {
            return estimate
        }
        var estimate = ColumnarCollectionViewLayoutHeightEstimate(precalculated: false, height: 60)
        guard let placeholderCell = layoutManager.placeholder(forCellWithReuseIdentifier: ArticleRightAlignedImageCollectionViewCell.identifier) as? ArticleRightAlignedImageCollectionViewCell else {
            return estimate
        }
        configure(cell: placeholderCell, forItemAt: indexPath, layoutOnly: true)
        // intentionally set all text and unhide image view to get largest possible size
        placeholderCell.isImageViewHidden = false
        placeholderCell.titleLabel.text = "any"
        placeholderCell.descriptionLabel.text = "any"
        estimate.height = placeholderCell.sizeThatFits(CGSize(width: columnWidth, height: UIViewNoIntrinsicMetric), apply: false).height
        estimate.precalculated = true
        cellLayoutEstimate = estimate
        return estimate
    }
    
    override func metrics(with size: CGSize, readableWidth: CGFloat, layoutMargins: UIEdgeInsets) -> ColumnarCollectionViewLayoutMetrics {
        return ColumnarCollectionViewLayoutMetrics.tableViewMetrics(with: size, readableWidth: readableWidth, layoutMargins: layoutMargins)
    }
}
<commit_msg>fix typo<commit_after>import UIKit

@objc(WMFArticleCollectionViewControllerDelegate)
protocol ArticleCollectionViewControllerDelegate: NSObjectProtocol {
    func articleCollectionViewController(_ articleCollectionViewController: ArticleCollectionViewController, didSelectArticleWithURL: URL, at indexPath: IndexPath)
}

@objc(WMFArticleCollectionViewController)
class ArticleCollectionViewController: ColumnarCollectionViewController, ReadingListHintPresenter, EditableCollection, EventLoggingEventValuesProviding {
    @objc var dataStore: MWKDataStore! {
        didSet {
            readingListHintController = ReadingListHintController(dataStore: dataStore, presenter: self)
        }
    }
    var cellLayoutEstimate: ColumnarCollectionViewLayoutHeightEstimate?

    var editController: CollectionViewEditController!
    var readingListHintController: ReadingListHintController?
    
    @objc weak var delegate: ArticleCollectionViewControllerDelegate?

    var feedFunnelContext: FeedFunnelContext?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        layoutManager.register(ArticleRightAlignedImageCollectionViewCell.self, forCellWithReuseIdentifier: ArticleRightAlignedImageCollectionViewCell.identifier, addPlaceholder: true)
        setupEditController()
    }
    
    open func configure(cell: ArticleRightAlignedImageCollectionViewCell, forItemAt indexPath: IndexPath, layoutOnly: Bool) {
        guard let article = article(at: indexPath) else {
            return
        }
        cell.configure(article: article, displayType: .compactList, index: indexPath.item, shouldShowSeparators: true, theme: theme, layoutOnly: layoutOnly)
        cell.topSeparator.isHidden = indexPath.item == 0
        cell.bottomSeparator.isHidden = indexPath.item == self.collectionView(collectionView, numberOfItemsInSection: indexPath.section) - 1
        cell.layoutMargins = layout.itemLayoutMargins
        editController.configureSwipeableCell(cell, forItemAt: indexPath, layoutOnly: layoutOnly)
    }
    
    open func articleURL(at indexPath: IndexPath) -> URL? {
        assert(false, "Subclassers should override this function")
        return nil
    }
    
    open func imageURL(at indexPath: IndexPath) -> URL? {
        guard let article = article(at: indexPath) else {
            return nil
        }
        return article.imageURL(forWidth: traitCollection.wmf_nearbyThumbnailWidth)
    }
    
    override func imageURLsForItemAt(_ indexPath: IndexPath) -> Set<URL>? {
        guard let imageURL = imageURL(at: indexPath) else {
            return nil
        }
        return [imageURL]
    }
    
    open func article(at indexPath: IndexPath) -> WMFArticle? {
        assert(false, "Subclassers should override this function")
        return nil
    }
    
    open func delete(at indexPath: IndexPath) {
        assert(false, "Subclassers should override this function")
    }
    
    open func canDelete(at indexPath: IndexPath) -> Bool {
        return false
    }
    
    open func canSave(at indexPath: IndexPath) -> Bool {
        guard let articleURL = articleURL(at: indexPath) else {
            return false
        }
        return !dataStore.savedPageList.isSaved(articleURL)
    }
    
    open func canUnsave(at indexPath: IndexPath) -> Bool {
        guard let articleURL = articleURL(at: indexPath) else {
            return false
        }
        return dataStore.savedPageList.isSaved(articleURL)
    }
    
    open func canShare(at indexPath: IndexPath) -> Bool {
        return articleURL(at: indexPath) != nil
    }
    
    override func contentSizeCategoryDidChange(_ notification: Notification?) {
        cellLayoutEstimate = nil
        super.contentSizeCategoryDidChange(notification)
    }
    
    // MARK: - EventLoggingEventValuesProviding
    
    var eventLoggingCategory: EventLoggingCategory {
        assertionFailure("Subclassers should override this property")
        return .unknown
    }
    
    var eventLoggingLabel: EventLoggingLabel? {
        return nil
    }

    var eventLoggingIndex: NSNumber? {
        guard let index = previewedIndexPath?.item else {
            return nil
        }
        return NSNumber(value: index)
    }

    var previewedIndexPath: IndexPath?

    // MARK: - Layout
    
    override func collectionView(_ collectionView: UICollectionView, estimatedHeightForItemAt indexPath: IndexPath, forColumnWidth columnWidth: CGFloat) -> ColumnarCollectionViewLayoutHeightEstimate {
        // The layout estimate can be re-used in this case because both labels are one line, meaning the cell
        // size only varies with font size. The layout estimate is nil'd when the font size changes on trait collection change
        if let estimate = cellLayoutEstimate {
            return estimate
        }
        var estimate = ColumnarCollectionViewLayoutHeightEstimate(precalculated: false, height: 60)
        guard let placeholderCell = layoutManager.placeholder(forCellWithReuseIdentifier: ArticleRightAlignedImageCollectionViewCell.identifier) as? ArticleRightAlignedImageCollectionViewCell else {
            return estimate
        }
        configure(cell: placeholderCell, forItemAt: indexPath, layoutOnly: true)
        // intentionally set all text and unhide image view to get largest possible size
        placeholderCell.isImageViewHidden = false
        placeholderCell.titleLabel.text = "any"
        placeholderCell.descriptionLabel.text = "any"
        estimate.height = placeholderCell.sizeThatFits(CGSize(width: columnWidth, height: UIViewNoIntrinsicMetric), apply: false).height
        estimate.precalculated = true
        cellLayoutEstimate = estimate
        return estimate
    }
    
    override func metrics(with size: CGSize, readableWidth: CGFloat, layoutMargins: UIEdgeInsets) -> ColumnarCollectionViewLayoutMetrics {
        return ColumnarCollectionViewLayoutMetrics.tableViewMetrics(with: size, readableWidth: readableWidth, layoutMargins: layoutMargins)
    }
}

{'fraction_non_alphanumeric': 0.06498254944324414, 'fraction_numerical': 0.0006647831145088915, 'mean_word_length': 3.3229166666666665, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7482119', 'n_tokens_mistral': 3107, 'n_tokens_neox': 3024, 'n_words': 791}