Full Code of Instagram/IGListKit for AI

main 01887c6e16e0 cached
574 files
4.8 MB
1.3M tokens
72 symbols
1 requests
Download .txt
Showing preview only (5,113K chars total). Download the full file or copy to clipboard to get everything.
Repository: Instagram/IGListKit
Branch: main
Commit: 01887c6e16e0
Files: 574
Total size: 4.8 MB

Directory structure:
gitextract_na4i75rs/

├── .github/
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── RELEASE_CHECKLIST.md
│   └── workflows/
│       └── CI.yml
├── .gitignore
├── .slather.yml
├── .swiftlint.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dangerfile
├── Examples/
│   ├── Examples-iOS/
│   │   ├── IGListKitExamples/
│   │   │   ├── AppDelegate.swift
│   │   │   ├── Assets.xcassets/
│   │   │   │   └── AppIcon.appiconset/
│   │   │   │       └── Contents.json
│   │   │   ├── Base.lproj/
│   │   │   │   └── LaunchScreen.storyboard
│   │   │   ├── DelegateProtocols/
│   │   │   │   └── PostSectionControllerDelegate.swift
│   │   │   ├── Extensions/
│   │   │   │   ├── UIActivityIndicatorView+Extension.swift
│   │   │   │   └── UIColor+Extension.swift
│   │   │   ├── IGListKitExamples.entitlements
│   │   │   ├── Info.plist
│   │   │   ├── Models/
│   │   │   │   ├── APIService.swift
│   │   │   │   ├── ActivityItem.swift
│   │   │   │   ├── FeedItem.swift
│   │   │   │   ├── GridItem.swift
│   │   │   │   ├── HorizontalCardsSection.swift
│   │   │   │   ├── LoadingCellModel.swift
│   │   │   │   ├── Month.swift
│   │   │   │   ├── Post.h
│   │   │   │   ├── Post.m
│   │   │   │   ├── PostModel.swift
│   │   │   │   ├── RemodelGeneratedModels/
│   │   │   │   │   ├── PersonModel.h
│   │   │   │   │   ├── PersonModel.m
│   │   │   │   │   └── PersonModel.value
│   │   │   │   ├── SelectionModel.swift
│   │   │   │   ├── SwipeActionSection.swift
│   │   │   │   ├── User.swift
│   │   │   │   └── ViewModels/
│   │   │   │       ├── DayViewModel.swift
│   │   │   │       └── MonthTitleViewModel.swift
│   │   │   ├── SectionControllers/
│   │   │   │   ├── DemoSectionController.swift
│   │   │   │   ├── DisplaySectionController.swift
│   │   │   │   ├── EmbeddedSectionController.swift
│   │   │   │   ├── ExpandableSectionController.swift
│   │   │   │   ├── FeedItemSectionController.swift
│   │   │   │   ├── GridSectionController.swift
│   │   │   │   ├── HorizontalSectionController.swift
│   │   │   │   ├── LabelSectionController.swift
│   │   │   │   ├── ListeningSectionController.swift
│   │   │   │   ├── LoadingSectionController.swift
│   │   │   │   ├── MonthSectionController.swift
│   │   │   │   ├── PersonSectionController.h
│   │   │   │   ├── PersonSectionController.m
│   │   │   │   ├── PostSectionController.h
│   │   │   │   ├── PostSectionController.m
│   │   │   │   ├── PostSectionController.swift
│   │   │   │   ├── RemoveSectionController.swift
│   │   │   │   ├── ReorderableSectionController.swift
│   │   │   │   ├── SearchSectionController.swift
│   │   │   │   ├── SelfSizingSectionController.swift
│   │   │   │   ├── StoryboardLabelSectionController.swift
│   │   │   │   ├── UserSectionController.swift
│   │   │   │   ├── With Composable Layout/
│   │   │   │   │   ├── ActivityComposableSectionController.swift
│   │   │   │   │   ├── ExpandableComposableSectionController.swift
│   │   │   │   │   ├── GridComposableSectionController.swift
│   │   │   │   │   ├── HorizontalComposableSectionController.swift
│   │   │   │   │   ├── SelectionComposableSectionController.swift
│   │   │   │   │   ├── SwipeActionComposabelSectionController.swift
│   │   │   │   │   └── UserComposableSectionController.swift
│   │   │   │   └── WorkingRangeSectionController.swift
│   │   │   ├── Storyboard/
│   │   │   │   └── Demo.storyboard
│   │   │   ├── Systems/
│   │   │   │   └── IncrementAnnouncer.swift
│   │   │   ├── ViewControllers/
│   │   │   │   ├── AnnouncingDepsViewController.swift
│   │   │   │   ├── CalendarViewController.swift
│   │   │   │   ├── CompositionLayoutViewController.swift
│   │   │   │   ├── DemosViewController.swift
│   │   │   │   ├── DiffTableViewController.swift
│   │   │   │   ├── DisplayViewController.swift
│   │   │   │   ├── EmptyViewController.swift
│   │   │   │   ├── FeedViewController.swift
│   │   │   │   ├── IGListKitExamples-Bridging-Header.h
│   │   │   │   ├── LoadMoreViewController.swift
│   │   │   │   ├── MixedDataViewController.swift
│   │   │   │   ├── NestedAdapterViewController.swift
│   │   │   │   ├── ObjcDemoViewController.h
│   │   │   │   ├── ObjcDemoViewController.m
│   │   │   │   ├── ObjcGeneratedModelDemoViewController.h
│   │   │   │   ├── ObjcGeneratedModelDemoViewController.m
│   │   │   │   ├── ReorderableViewController.swift
│   │   │   │   ├── SearchViewController.swift
│   │   │   │   ├── SelfSizingCellsViewController.swift
│   │   │   │   ├── SingleSectionStoryboardViewController.swift
│   │   │   │   ├── SingleSectionViewController.swift
│   │   │   │   ├── StoryboardViewController.swift
│   │   │   │   ├── SupplementaryViewController.swift
│   │   │   │   └── WorkingRangeViewController.swift
│   │   │   └── Views/
│   │   │       ├── CalendarDayCell.swift
│   │   │       ├── CenterLabelCell.swift
│   │   │       ├── CommentCell.h
│   │   │       ├── CommentCell.m
│   │   │       ├── CompositionLayoutCell.swift
│   │   │       ├── DetailLabelCell.swift
│   │   │       ├── EmbeddedCollectionViewCell.swift
│   │   │       ├── FullWidthSelfSizingCell.swift
│   │   │       ├── ImageCell.swift
│   │   │       ├── InteractiveCell.h
│   │   │       ├── InteractiveCell.m
│   │   │       ├── LabelCell.swift
│   │   │       ├── LoadingCell.swift
│   │   │       ├── ManuallySelfSizingCell.swift
│   │   │       ├── MonthTitleCell.swift
│   │   │       ├── NibCell.swift
│   │   │       ├── NibCell.xib
│   │   │       ├── NibSelfSizingCell.swift
│   │   │       ├── NibSelfSizingCell.xib
│   │   │       ├── PersonCell.h
│   │   │       ├── PersonCell.m
│   │   │       ├── PhotoCell.h
│   │   │       ├── PhotoCell.m
│   │   │       ├── PostCell.swift
│   │   │       ├── RemoveCell.swift
│   │   │       ├── SearchCell.swift
│   │   │       ├── SpinnerCell.swift
│   │   │       ├── StoryboardCell.swift
│   │   │       ├── UserFooterView.swift
│   │   │       ├── UserFooterView.xib
│   │   │       ├── UserHeaderView.swift
│   │   │       ├── UserHeaderView.xib
│   │   │       ├── UserInfoCell.h
│   │   │       └── UserInfoCell.m
│   │   ├── IGListKitExamples-UITests/
│   │   │   ├── DemosViewControllerUITests.swift
│   │   │   ├── FeedViewController.swift
│   │   │   ├── Info.plist
│   │   │   ├── LoadMoreViewControllerUITests.swift
│   │   │   ├── MixedDataViewControllerUITests.swift
│   │   │   ├── SearchViewControllerUITests.swift
│   │   │   └── UITestCase.swift
│   │   ├── IGListKitExamples.xcodeproj/
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata/
│   │   │       └── xcschemes/
│   │   │           ├── IGListKitExamples.xcscheme
│   │   │           ├── IGListKitMessageExample.xcscheme
│   │   │           └── IGListKitTodayExample.xcscheme
│   │   ├── IGListKitMessageExample/
│   │   │   ├── Assets.xcassets/
│   │   │   │   ├── Contents.json
│   │   │   │   └── iMessage App Icon.stickersiconset/
│   │   │   │       └── Contents.json
│   │   │   ├── Info.plist
│   │   │   └── MessagesViewController.swift
│   │   ├── IGListKitTodayExample/
│   │   │   ├── Info.plist
│   │   │   └── TodayViewController.swift
│   │   └── LICENSE-examples.md
│   ├── Examples-macOS/
│   │   ├── IGListKitExamples/
│   │   │   ├── AppDelegate.swift
│   │   │   ├── Assets.xcassets/
│   │   │   │   └── AppIcon.appiconset/
│   │   │   │       └── Contents.json
│   │   │   ├── Base.lproj/
│   │   │   │   └── Main.storyboard
│   │   │   ├── Data/
│   │   │   │   └── users.json
│   │   │   ├── Helpers/
│   │   │   │   ├── IndexSet+Extensions.swift
│   │   │   │   ├── Shuffle.swift
│   │   │   │   └── UsersProvider.swift
│   │   │   ├── Info.plist
│   │   │   ├── Models/
│   │   │   │   └── User.swift
│   │   │   ├── View/
│   │   │   │   ├── UserCollectionViewCell.swift
│   │   │   │   └── UserCollectionViewCell.xib
│   │   │   └── ViewControllers/
│   │   │       └── UsersViewController.swift
│   │   ├── IGListKitExamples.xcodeproj/
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata/
│   │   │       └── xcschemes/
│   │   │           └── IGListKitExamples.xcscheme
│   │   └── LICENSE-examples.md
│   └── Examples-tvOS/
│       ├── IGListKitExamples/
│       │   ├── AppDelegate.swift
│       │   ├── Assets.xcassets/
│       │   │   ├── App Icon & Top Shelf Image.brandassets/
│       │   │   │   ├── App Icon - Large.imagestack/
│       │   │   │   │   ├── Back.imagestacklayer/
│       │   │   │   │   │   ├── Content.imageset/
│       │   │   │   │   │   │   └── Contents.json
│       │   │   │   │   │   └── Contents.json
│       │   │   │   │   ├── Contents.json
│       │   │   │   │   ├── Front.imagestacklayer/
│       │   │   │   │   │   ├── Content.imageset/
│       │   │   │   │   │   │   └── Contents.json
│       │   │   │   │   │   └── Contents.json
│       │   │   │   │   └── Middle.imagestacklayer/
│       │   │   │   │       ├── Content.imageset/
│       │   │   │   │       │   └── Contents.json
│       │   │   │   │       └── Contents.json
│       │   │   │   ├── App Icon - Small.imagestack/
│       │   │   │   │   ├── Back.imagestacklayer/
│       │   │   │   │   │   ├── Content.imageset/
│       │   │   │   │   │   │   └── Contents.json
│       │   │   │   │   │   └── Contents.json
│       │   │   │   │   ├── Contents.json
│       │   │   │   │   ├── Front.imagestacklayer/
│       │   │   │   │   │   ├── Content.imageset/
│       │   │   │   │   │   │   └── Contents.json
│       │   │   │   │   │   └── Contents.json
│       │   │   │   │   └── Middle.imagestacklayer/
│       │   │   │   │       ├── Content.imageset/
│       │   │   │   │       │   └── Contents.json
│       │   │   │   │       └── Contents.json
│       │   │   │   ├── Contents.json
│       │   │   │   ├── Top Shelf Image Wide.imageset/
│       │   │   │   │   └── Contents.json
│       │   │   │   └── Top Shelf Image.imageset/
│       │   │   │       └── Contents.json
│       │   │   ├── Contents.json
│       │   │   └── LaunchImage.launchimage/
│       │   │       └── Contents.json
│       │   ├── Info.plist
│       │   ├── Models/
│       │   │   └── NSObject+IGListDiffable.swift
│       │   ├── SectionControllers/
│       │   │   ├── CarouselSectionController.swift
│       │   │   ├── DemoSectionController.swift
│       │   │   ├── HorizontalSectionController.swift
│       │   │   └── LabelSectionController.swift
│       │   ├── ViewControllers/
│       │   │   ├── DemosViewController.swift
│       │   │   └── NestedAdapterViewController.swift
│       │   └── Views/
│       │       ├── CarouselCell.swift
│       │       ├── CarouselCell.xib
│       │       ├── DemoCell.swift
│       │       ├── EmbeddedCollectionViewCell.swift
│       │       └── LabelCell.swift
│       ├── IGListKitExamples.xcodeproj/
│       │   ├── project.pbxproj
│       │   └── xcshareddata/
│       │       └── xcschemes/
│       │           └── IGListKitExamples.xcscheme
│       └── LICENSE-examples.md
├── Gemfile
├── Guides/
│   ├── Best Practices and FAQ.md
│   ├── Generating your models using remodel.md
│   ├── Getting Started.md
│   ├── IGListDiffable and Equality.md
│   ├── Installation.md
│   ├── Migration.md
│   ├── Modeling and Binding.md
│   ├── VISION.md
│   ├── Working with Core Data.md
│   └── Working with UICollectionView.md
├── IGListDiffKit.podspec
├── IGListKit.podspec
├── IGListKit.xcodeproj/
│   ├── project.pbxproj
│   └── xcshareddata/
│       └── xcschemes/
│           ├── IGListKit-macOS.xcscheme
│           ├── IGListKit-tvOS.xcscheme
│           └── IGListKit.xcscheme
├── IGListSwiftKit.podspec
├── LICENSE.md
├── Package.swift
├── README.md
├── README.zh.md
├── Source/
│   ├── IGListDiffKit/
│   │   ├── IGListAssert.h
│   │   ├── IGListBatchUpdateData.h
│   │   ├── IGListBatchUpdateData.mm
│   │   ├── IGListCompatibility.h
│   │   ├── IGListDiff.h
│   │   ├── IGListDiff.mm
│   │   ├── IGListDiffKit.h
│   │   ├── IGListDiffable.h
│   │   ├── IGListExperiments.h
│   │   ├── IGListIndexPathResult.h
│   │   ├── IGListIndexPathResult.m
│   │   ├── IGListIndexSetResult.h
│   │   ├── IGListIndexSetResult.m
│   │   ├── IGListMacros.h
│   │   ├── IGListMoveIndex.h
│   │   ├── IGListMoveIndex.m
│   │   ├── IGListMoveIndexPath.h
│   │   ├── IGListMoveIndexPath.m
│   │   ├── Internal/
│   │   │   ├── IGListIndexPathResultInternal.h
│   │   │   ├── IGListIndexSetResultInternal.h
│   │   │   ├── IGListMoveIndexInternal.h
│   │   │   └── IGListMoveIndexPathInternal.h
│   │   ├── NSNumber+IGListDiffable.h
│   │   ├── NSNumber+IGListDiffable.m
│   │   ├── NSString+IGListDiffable.h
│   │   └── NSString+IGListDiffable.m
│   ├── IGListKit/
│   │   ├── IGListAdapter.h
│   │   ├── IGListAdapter.m
│   │   ├── IGListAdapterDataSource.h
│   │   ├── IGListAdapterDelegate.h
│   │   ├── IGListAdapterDelegateAnnouncer.h
│   │   ├── IGListAdapterDelegateAnnouncer.m
│   │   ├── IGListAdapterMoveDelegate.h
│   │   ├── IGListAdapterPerformanceDelegate.h
│   │   ├── IGListAdapterUpdateListener.h
│   │   ├── IGListAdapterUpdater.h
│   │   ├── IGListAdapterUpdater.m
│   │   ├── IGListAdapterUpdaterDelegate.h
│   │   ├── IGListBatchContext.h
│   │   ├── IGListBindable.h
│   │   ├── IGListBindingSectionController.h
│   │   ├── IGListBindingSectionController.m
│   │   ├── IGListBindingSectionControllerDataSource.h
│   │   ├── IGListBindingSectionControllerSelectionDelegate.h
│   │   ├── IGListBindingSingleSectionController.h
│   │   ├── IGListBindingSingleSectionController.m
│   │   ├── IGListCollectionContext.h
│   │   ├── IGListCollectionScrollingTraits.h
│   │   ├── IGListCollectionView.h
│   │   ├── IGListCollectionView.m
│   │   ├── IGListCollectionViewDelegateLayout.h
│   │   ├── IGListCollectionViewLayout.h
│   │   ├── IGListCollectionViewLayout.mm
│   │   ├── IGListCollectionViewLayoutCompatible.h
│   │   ├── IGListCollectionViewLayoutInvalidationContext.h
│   │   ├── IGListCollectionViewLayoutInvalidationContext.m
│   │   ├── IGListDisplayDelegate.h
│   │   ├── IGListGenericSectionController.h
│   │   ├── IGListGenericSectionController.m
│   │   ├── IGListKit.h
│   │   ├── IGListReloadDataUpdater.h
│   │   ├── IGListReloadDataUpdater.m
│   │   ├── IGListScrollDelegate.h
│   │   ├── IGListSectionController.h
│   │   ├── IGListSectionController.m
│   │   ├── IGListSingleSectionController.h
│   │   ├── IGListSingleSectionController.m
│   │   ├── IGListSupplementaryViewSource.h
│   │   ├── IGListTransitionData.h
│   │   ├── IGListTransitionData.m
│   │   ├── IGListTransitionDelegate.h
│   │   ├── IGListUpdatingDelegate.h
│   │   ├── IGListWorkingRangeDelegate.h
│   │   ├── Internal/
│   │   │   ├── IGListAdapter+DebugDescription.h
│   │   │   ├── IGListAdapter+DebugDescription.m
│   │   │   ├── IGListAdapter+UICollectionView.h
│   │   │   ├── IGListAdapter+UICollectionView.m
│   │   │   ├── IGListAdapterDelegateAnnouncerInternal.h
│   │   │   ├── IGListAdapterInternal.h
│   │   │   ├── IGListAdapterProxy.h
│   │   │   ├── IGListAdapterProxy.m
│   │   │   ├── IGListAdapterUpdater+DebugDescription.h
│   │   │   ├── IGListAdapterUpdater+DebugDescription.m
│   │   │   ├── IGListAdapterUpdaterHelpers.h
│   │   │   ├── IGListAdapterUpdaterHelpers.m
│   │   │   ├── IGListAdapterUpdaterInternal.h
│   │   │   ├── IGListArrayUtilsInternal.h
│   │   │   ├── IGListArrayUtilsInternal.m
│   │   │   ├── IGListBatchUpdateData+DebugDescription.h
│   │   │   ├── IGListBatchUpdateData+DebugDescription.m
│   │   │   ├── IGListBatchUpdateState.h
│   │   │   ├── IGListBatchUpdateTransaction.h
│   │   │   ├── IGListBatchUpdateTransaction.m
│   │   │   ├── IGListBindingSectionController+DebugDescription.h
│   │   │   ├── IGListBindingSectionController+DebugDescription.m
│   │   │   ├── IGListCollectionViewLayoutInternal.h
│   │   │   ├── IGListDataSourceChangeTransaction.h
│   │   │   ├── IGListDataSourceChangeTransaction.m
│   │   │   ├── IGListDebugger.h
│   │   │   ├── IGListDebugger.m
│   │   │   ├── IGListDebuggingUtilities.h
│   │   │   ├── IGListDebuggingUtilities.m
│   │   │   ├── IGListDefaultExperiments.h
│   │   │   ├── IGListDisplayHandler.h
│   │   │   ├── IGListDisplayHandler.m
│   │   │   ├── IGListItemUpdatesCollector.h
│   │   │   ├── IGListItemUpdatesCollector.m
│   │   │   ├── IGListPerformDiff.h
│   │   │   ├── IGListPerformDiff.m
│   │   │   ├── IGListReloadIndexPath.h
│   │   │   ├── IGListReloadIndexPath.m
│   │   │   ├── IGListReloadTransaction.h
│   │   │   ├── IGListReloadTransaction.m
│   │   │   ├── IGListSectionControllerInternal.h
│   │   │   ├── IGListSectionMap+DebugDescription.h
│   │   │   ├── IGListSectionMap+DebugDescription.m
│   │   │   ├── IGListSectionMap.h
│   │   │   ├── IGListSectionMap.m
│   │   │   ├── IGListUpdateCoalescer.h
│   │   │   ├── IGListUpdateCoalescer.m
│   │   │   ├── IGListUpdateTransactable.h
│   │   │   ├── IGListUpdateTransactionBuilder.h
│   │   │   ├── IGListUpdateTransactionBuilder.m
│   │   │   ├── IGListViewVisibilityTracker.h
│   │   │   ├── IGListViewVisibilityTracker.m
│   │   │   ├── IGListViewVisibilityTrackerInternal.h
│   │   │   ├── IGListWorkingRangeHandler.h
│   │   │   ├── IGListWorkingRangeHandler.mm
│   │   │   ├── UICollectionView+DebugDescription.h
│   │   │   ├── UICollectionView+DebugDescription.m
│   │   │   ├── UICollectionView+IGListBatchUpdateData.h
│   │   │   ├── UICollectionView+IGListBatchUpdateData.m
│   │   │   ├── UICollectionViewLayout+InteractiveReordering.h
│   │   │   ├── UICollectionViewLayout+InteractiveReordering.m
│   │   │   ├── UIScrollView+IGListKit.h
│   │   │   ├── UIScrollView+IGListKit.m
│   │   │   └── UIViewController+IGListAdapterInternal.h
│   │   ├── UIViewController+IGListAdapter.h
│   │   └── UIViewController+IGListAdapter.m
│   ├── IGListSwiftKit/
│   │   ├── IGListAdapter+Async.swift
│   │   ├── IGListCollectionContext+Refinements.swift
│   │   ├── IGListSingleSectionController+Refinements.swift
│   │   ├── IGListSwiftKit.h
│   │   ├── ListIdentifiable.swift
│   │   └── ListValueSectionController.swift
│   └── Info.plist
├── Tests/
│   ├── Assets/
│   │   ├── IGTestNibCell.xib
│   │   ├── IGTestNibSupplementaryView.xib
│   │   └── IGTestStoryboard.storyboard
│   ├── IGListAdapterDelegateAnnouncerTests.m
│   ├── IGListAdapterE2ETests.m
│   ├── IGListAdapterProxyTests.m
│   ├── IGListAdapterStoryboardTests.m
│   ├── IGListAdapterTests.m
│   ├── IGListAdapterUpdaterTests.m
│   ├── IGListBatchUpdateDataTests.m
│   ├── IGListBindingSectionControllerTests.m
│   ├── IGListBindingSingleSectionControllerTests.m
│   ├── IGListCollectionScrollingTraitsTests.m
│   ├── IGListCollectionViewLayoutTests.m
│   ├── IGListCollectionViewTests.m
│   ├── IGListContentInsetTests.m
│   ├── IGListDebugDescriptionTests.m
│   ├── IGListDebuggerTests.m
│   ├── IGListDiffDescriptionStringTests.m
│   ├── IGListDiffResultTests.m
│   ├── IGListDiffSwiftTests.swift
│   ├── IGListDiffTests.h
│   ├── IGListDiffTests.m
│   ├── IGListDisplayHandlerTests.m
│   ├── IGListGenericSectionControllerTests.m
│   ├── IGListInteractiveMovingTests.m
│   ├── IGListItemUpdatesCollectorTests.m
│   ├── IGListKitTests-Bridging-Header.h
│   ├── IGListPerformDiffTests.m
│   ├── IGListReloadDataUpdaterTests.m
│   ├── IGListSectionControllerTests.m
│   ├── IGListSectionMapTests.m
│   ├── IGListSingleNibItemControllerTests.m
│   ├── IGListSingleSectionControllerTests.m
│   ├── IGListSingleStoryboardItemControllerTests.m
│   ├── IGListTestCase.h
│   ├── IGListTestCase.m
│   ├── IGListTestHelpers.h
│   ├── IGListTransactionTests.m
│   ├── IGListUpdateCoalescerTests.m
│   ├── IGListViewVisibilityTrackerTests.m
│   ├── IGListWorkingRangeHandlerTests.m
│   ├── Info.plist
│   ├── Objects/
│   │   ├── IGLayoutTestDataSource.h
│   │   ├── IGLayoutTestDataSource.m
│   │   ├── IGLayoutTestItem.h
│   │   ├── IGLayoutTestItem.m
│   │   ├── IGLayoutTestSection.h
│   │   ├── IGLayoutTestSection.m
│   │   ├── IGListAdapterUpdateTester.h
│   │   ├── IGListAdapterUpdateTester.m
│   │   ├── IGListTestAdapterDataSource.h
│   │   ├── IGListTestAdapterDataSource.m
│   │   ├── IGListTestAdapterHorizontalDataSource.h
│   │   ├── IGListTestAdapterHorizontalDataSource.m
│   │   ├── IGListTestAdapterReorderingDataSource.h
│   │   ├── IGListTestAdapterReorderingDataSource.m
│   │   ├── IGListTestAdapterStoryboardDataSource.h
│   │   ├── IGListTestAdapterStoryboardDataSource.m
│   │   ├── IGListTestCollectionViewLayout.h
│   │   ├── IGListTestCollectionViewLayout.m
│   │   ├── IGListTestContainerSizeSection.h
│   │   ├── IGListTestContainerSizeSection.m
│   │   ├── IGListTestHorizontalSection.h
│   │   ├── IGListTestHorizontalSection.m
│   │   ├── IGListTestOffsettingLayout.h
│   │   ├── IGListTestOffsettingLayout.m
│   │   ├── IGListTestSection.h
│   │   ├── IGListTestSection.m
│   │   ├── IGListTestStoryboardSection.h
│   │   ├── IGListTestStoryboardSection.m
│   │   ├── IGListTestUICollectionViewDataSource.h
│   │   ├── IGListTestUICollectionViewDataSource.m
│   │   ├── IGTestBindingSingleItemDataSource.h
│   │   ├── IGTestBindingSingleItemDataSource.m
│   │   ├── IGTestBindingWithoutDeselectionDelegate.h
│   │   ├── IGTestBindingWithoutDeselectionDelegate.m
│   │   ├── IGTestCell.h
│   │   ├── IGTestCell.m
│   │   ├── IGTestDelegateController.h
│   │   ├── IGTestDelegateController.m
│   │   ├── IGTestDelegateDataSource.h
│   │   ├── IGTestDelegateDataSource.m
│   │   ├── IGTestDiffingDataSource.h
│   │   ├── IGTestDiffingDataSource.m
│   │   ├── IGTestDiffingObject.h
│   │   ├── IGTestDiffingObject.m
│   │   ├── IGTestDiffingSectionController.h
│   │   ├── IGTestDiffingSectionController.m
│   │   ├── IGTestInvalidateLayoutDataSource.h
│   │   ├── IGTestInvalidateLayoutDataSource.m
│   │   ├── IGTestInvalidateLayoutObject.h
│   │   ├── IGTestInvalidateLayoutObject.m
│   │   ├── IGTestInvalidateLayoutSectionController.h
│   │   ├── IGTestInvalidateLayoutSectionController.m
│   │   ├── IGTestNibSupplementaryView.h
│   │   ├── IGTestNibSupplementaryView.m
│   │   ├── IGTestNumberBindableCell.h
│   │   ├── IGTestNumberBindableCell.m
│   │   ├── IGTestObject.h
│   │   ├── IGTestObject.m
│   │   ├── IGTestReorderableSection.h
│   │   ├── IGTestReorderableSection.m
│   │   ├── IGTestSingleItemDataSource.h
│   │   ├── IGTestSingleItemDataSource.m
│   │   ├── IGTestSingleNibItemDataSource.h
│   │   ├── IGTestSingleNibItemDataSource.m
│   │   ├── IGTestSingleStoryboardItemDataSource.h
│   │   ├── IGTestSingleStoryboardItemDataSource.m
│   │   ├── IGTestSingleWithoutDeselectionDelegate.h
│   │   ├── IGTestSingleWithoutDeselectionDelegate.m
│   │   ├── IGTestStoryboardCell.h
│   │   ├── IGTestStoryboardCell.m
│   │   ├── IGTestStoryboardSupplementarySource.h
│   │   ├── IGTestStoryboardSupplementarySource.m
│   │   ├── IGTestStoryboardSupplementaryView.h
│   │   ├── IGTestStoryboardSupplementaryView.m
│   │   ├── IGTestStoryboardViewController.h
│   │   ├── IGTestStoryboardViewController.m
│   │   ├── IGTestStringBindableCell.h
│   │   ├── IGTestStringBindableCell.m
│   │   ├── IGTestSupplementarySource.h
│   │   └── IGTestSupplementarySource.m
│   └── UIViewControllerIGListAdapterTests.m
├── docs/
│   ├── Categories/
│   │   └── UIViewController(IGListAdapter).html
│   ├── Categories.html
│   ├── Classes/
│   │   ├── IGListAdapter.html
│   │   ├── IGListAdapterDelegateAnnouncer.html
│   │   ├── IGListAdapterUpdater.html
│   │   ├── IGListBatchUpdateData.html
│   │   ├── IGListBindingSectionController.html
│   │   ├── IGListBindingSingleSectionController.html
│   │   ├── IGListCollectionView.html
│   │   ├── IGListCollectionViewLayout.html
│   │   ├── IGListCollectionViewLayoutInvalidationContext.html
│   │   ├── IGListGenericSectionController.html
│   │   ├── IGListIndexPathResult.html
│   │   ├── IGListIndexSetResult.html
│   │   ├── IGListMoveIndex.html
│   │   ├── IGListMoveIndexPath.html
│   │   ├── IGListSectionController.html
│   │   ├── IGListSingleSectionController.html
│   │   └── IGListTransitionData.html
│   ├── Classes.html
│   ├── Constants.html
│   ├── Enums/
│   │   ├── IGListAdapterUpdateType.html
│   │   ├── IGListDiffOption.html
│   │   └── IGListExperiment.html
│   ├── Enums.html
│   ├── Functions.html
│   ├── Guides.html
│   ├── Protocols/
│   │   ├── IGListAdapterDataSource.html
│   │   ├── IGListAdapterDelegate.html
│   │   ├── IGListAdapterMoveDelegate.html
│   │   ├── IGListAdapterPerformanceDelegate.html
│   │   ├── IGListAdapterUpdateListener.html
│   │   ├── IGListAdapterUpdaterDelegate.html
│   │   ├── IGListBatchContext.html
│   │   ├── IGListBindable.html
│   │   ├── IGListBindingSectionControllerDataSource.html
│   │   ├── IGListBindingSectionControllerSelectionDelegate.html
│   │   ├── IGListCollectionContext.html
│   │   ├── IGListCollectionViewDelegateLayout.html
│   │   ├── IGListCollectionViewLayoutCompatible.html
│   │   ├── IGListDiffable.html
│   │   ├── IGListDisplayDelegate.html
│   │   ├── IGListScrollDelegate.html
│   │   ├── IGListSingleSectionControllerDelegate.html
│   │   ├── IGListSupplementaryViewSource.html
│   │   ├── IGListTransitionDelegate.html
│   │   ├── IGListUpdatingDelegate.html
│   │   └── IGListWorkingRangeDelegate.html
│   ├── Protocols.html
│   ├── Structs/
│   │   ├── IGListAdaptiveCoalescingExperimentConfig.html
│   │   ├── IGListAdaptiveDiffingExperimentConfig.html
│   │   └── IGListCollectionScrollingTraits.html
│   ├── Structs.html
│   ├── Type Definitions/
│   │   ├── IGListAdaptiveCoalescingExperimentConfig/
│   │   │   └── IGListAdaptiveCoalescingExperimentConfig.html
│   │   ├── IGListAdaptiveCoalescingExperimentConfig.html
│   │   ├── IGListAdaptiveDiffingExperimentConfig/
│   │   │   └── IGListAdaptiveDiffingExperimentConfig.html
│   │   ├── IGListAdaptiveDiffingExperimentConfig.html
│   │   ├── IGListCollectionScrollingTraits/
│   │   │   └── IGListCollectionScrollingTraits.html
│   │   └── IGListCollectionScrollingTraits.html
│   ├── Type Definitions.html
│   ├── best-practices-and-faq.html
│   ├── css/
│   │   ├── highlight.css
│   │   └── jazzy.css
│   ├── generating-your-models-using-remodel.html
│   ├── getting-started.html
│   ├── iglistdiffable-and-equality.html
│   ├── index.html
│   ├── installation.html
│   ├── js/
│   │   ├── jazzy.js
│   │   ├── jazzy.search.js
│   │   └── typeahead.jquery.js
│   ├── migration.html
│   ├── modeling-and-binding.html
│   ├── search.json
│   ├── undocumented.json
│   ├── vision.html
│   ├── working-with-core-data.html
│   └── working-with-uicollectionview.html
├── remodel-plugin/
│   ├── features/
│   │   └── iglistdiffable.feature
│   └── src/
│       ├── __tests__/
│       │   └── plugins/
│       │       └── iglistdiffable-test.ts
│       └── plugins/
│           ├── iglistdiffable-utils.ts
│           └── iglistdiffable.ts
└── scripts/
    ├── build_docs.sh
    ├── generate_spm_sources_layout.sh
    ├── lint.sh
    └── version.sh

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

================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to IGListKit

We want to make contributing to this project as easy and transparent as
possible, and actively welcome your pull requests.  If you run into problems,
please open an issue on GitHub.

## Pull Requests

1. Fork the repo and create your branch from `main`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. Make sure your code lints.
6. If you haven't already, complete the Contributor License Agreement ("CLA").
7. Add an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.

## Experimental changes

If your change can't be unit tested, we might ask that you add your change as an experiment so that we can verify your change works. To do this, first add a new option to [IGListExperiment](https://github.com/Instagram/IGListKit/blob/main/Source/Common/IGListExperiments.h#L17).

Then, use an `experiments` bitmask wherever your change is and wrap it in a check to see if it is enabled:

```swift
IGListExperimentEnabled(self.experiments, IGListExperimentMyAwesomeChange) {
    // your code here
}
```

Once your experiment is confirmed we will remove the option and wrapping check!

## How we do major and minor releases

Everything merges into `main`. When we cut a release, we merge from `main` into `stable`, tag, and push to CocoaPods.

*Example:*

If current release is `2.1.0`, then any commits for `2.2.0` go into `stable` while commits for `3.0` would go to `main`.

## Testing

Keep in mind that we want 99% test coverage at all times. If you add new code, please make sure it gets tested! When fixing bugs, try to reproduce the bug in a unit test and then fix the test. This makes sure we never regress that issue again.

## Contributor License Agreement ("CLA")

In order to accept your pull request, we need you to submit a CLA. You only need
to do this once to work on any of Facebook's open source projects.

Complete your CLA here: <https://code.facebook.com/cla>

## Issues

We use GitHub issues to track public bugs. Please ensure your description is
clear and has sufficient instructions to be able to reproduce the issue.

Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
disclosure of security bugs. In those cases, please go through the process
outlined on that page and do not file a public issue.

## Coding Style

* 4 spaces for indentation rather than tabs
* Public classes and methods must contain header documentation
* Use plain C functions instead of class methods whenever possible
* Restrict subclassing (`IGLK_SUBCLASSING_RESTRICTED` macro or `final` in Swift), unless the class is designed for subclassing.
* Use instance variables instead of properties
* Create local variables instead of repeatedly accessing properties like `self.property`. This results in a larger binary and extra `objc_msgSend(...)` calls.

## Updating Testing Dependencies

If you need a different version of one of the testing dependencies, you will need to first [install Cocoapods](https://guides.cocoapods.org/using/getting-started.html):

```
$ [sudo] gem install cocoapods
```

Then within the project directory, run `pod install` to update the dependency to that version.

## License

By contributing to `IGListKit`, you agree that your contributions will be licensed under the LICENSE file in the root directory of this source tree.


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
## New issue checklist

- [ ] I have reviewed the [`README`](https://github.com/Instagram/IGListKit/blob/main/README.md) and [documentation](http://instagram.github.io/IGListKit)
- [ ] I have searched [existing issues](https://github.com/Instagram/IGListKit/issues) and this is not a duplicate
- [ ] I have attempted to reproduce the issue and include an example project.

### General information

- `IGListKit` version:
- iOS version(s):
- CocoaPods/Carthage version:
- Xcode version:
- Devices/Simulators affected:
- Reproducible in the demo project? (Yes/No):
- Related issues:

### Debug information

```bash
# Please include debug logs using the following lldb command:
po [IGListDebugger dump]
```


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## Changes in this pull request

Issue fixed: #

### Checklist

- [ ] All tests pass. Demo project builds and runs.
- [ ] I added tests, an experiment, or detailed why my change isn't tested.
- [ ] I added an entry to the `CHANGELOG.md` for any breaking changes, enhancements, or bug fixes.
- [ ] I have reviewed the [contributing guide](https://github.com/Instagram/IGListKit/blob/main/.github/CONTRIBUTING.md)


================================================
FILE: .github/RELEASE_CHECKLIST.md
================================================
# Release Checklist

Here are the steps for creating and publishing a new release for `IGListKit`.

- Final review and update of header docs and guides
- Final review of changelog
- Regenerate docs
- Update pod spec version
- Update xcodeproj version
- Run `pod install` on all examples (**must happen on FB internal** because of sync issues)
- Merge `main` into `stable` via cmd-line and push
- Confirm `stable` is `0|0` [ahead/behind](https://github.com/Instagram/IGListKit/branches)
- Create [GitHub release](https://github.com/Instagram/IGListKit/releases) from `stable`
- Paste changelog into GH release notes
- Publish GitHub release
- Run `pod lib lint`
- Push updated podspec: `pod trunk push IGListKit.podspec`
- Verify new release on [CocoaPods](https://cocoapods.org/pods/IGListKit)
- Tweet all the tweets


================================================
FILE: .github/workflows/CI.yml
================================================
name: "IGListKit CI"

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - '*'

jobs:
  macOS:
    name: Unit Test macOS
    runs-on: macos-14
    env:
      DEVELOPER_DIR: /Applications/Xcode.app
      PROJECT_NAME: IGListKit.xcodeproj
      SCHEME_NAME: IGListKit-macOS
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Cache RubyGems
        uses: actions/cache@v3
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Install ruby gems.
        run: bundle install

      - name: Run unit tests for macOS
        run: |
          set -o pipefail
          xcodebuild build build-for-testing -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "platform=macOS" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
          xcodebuild analyze test-without-building -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "platform=macOS" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c

  iOS:
    name: Unit Test iOS
    runs-on: macos-14
    env:
      DEVELOPER_DIR: /Applications/Xcode.app
      PROJECT_NAME: IGListKit.xcodeproj
      SCHEME_NAME: IGListKit
    strategy:
      matrix:
        destination: ["platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.2"]
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Cache RubyGems
        uses: actions/cache@v3
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Install ruby gems.
        run: bundle install

      - name: iOS - ${{ matrix.destination }}
        run: |
          set -o pipefail
          xcodebuild build build-for-testing -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
          xcodebuild analyze test-without-building -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c

      - name: Upload code coverage
        run: bundle exec slather
        env:
          COVERAGE_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CI_PULL_REQUEST: ${{ github.event.number }}
          GIT_BRANCH: ${{ github.head_ref || github.ref_name }}

  tvOS:
    name: Unit Test tvOS
    runs-on: macos-14
    env:
      DEVELOPER_DIR: /Applications/Xcode.app
      PROJECT_NAME: IGListKit.xcodeproj
      SCHEME_NAME: IGListKit-tvOS
    strategy:
      matrix:
        destination: ["platform=tvOS Simulator,name=Apple TV,OS=18.2"]
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Cache RubyGems
        uses: actions/cache@v3
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Install ruby gems.
        run: bundle install

      - name: Run unit tests for tvOS
        run: |
          set -o pipefail
          xcodebuild build build-for-testing -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c
          xcodebuild analyze test-without-building -project "${{ env.PROJECT_NAME }}" -scheme "${{ env.SCHEME_NAME }}" -destination "${{ matrix.destination }}" -configuration Debug CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=YES | bundle exec xcpretty -c

  CocoaPods:
    name: CocoaPods Lint
    runs-on: macos-14
    env:
      DEVELOPER_DIR: /Applications/Xcode.app
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Cache RubyGems
        uses: actions/cache@v3
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Install ruby gems.
        run: bundle install

      - name: Run IGListDiffKit podspec lint
        run: bundle exec pod lib lint IGListDiffKit.podspec --allow-warnings

      - name: Run IGListKit podspec lint
        run: bundle exec pod lib lint IGListKit.podspec --allow-warnings "--include-podspecs=IGListDiffKit.podspec"

      - name: Run IGListSwiftKit podspec lint
        run: bundle exec pod lib lint IGListSwiftKit.podspec --allow-warnings "--include-podspecs=*.podspec"

  SPM-layout-generator:
    name: Verify generate_spm_sources_layout.sh is not broken
    runs-on: macos-14
    env:
      DEVELOPER_DIR: /Applications/Xcode.app
      PROJECT_NAME: IGListKit.xcodeproj
      IOS_DESTINATION: "platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.2"
      SPM_IG_LIST_DIFF_KIT_PUBLIC_HEADERS_PATH: "spm/Sources/IGListDiffKit/include"
      SPM_IG_LIST_DIFF_KIT_SOURCES_PATH: "spm/Sources/IGListDiffKit"
      SPM_IG_LIST_KIT_PUBLIC_HEADERS_PATH: "spm/Sources/IGListKit/include"
      SPM_IG_LIST_KIT_SOURCES_PATH: "spm/Sources/IGListKit"
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Manually clean SPM Sources folder
        run: |
            rm -rf "${{ env.SPM_IG_LIST_DIFF_KIT_PUBLIC_HEADERS_PATH }}/*.*"
            rm -rf "${{ env.SPM_IG_LIST_DIFF_KIT_SOURCES_PATH }}/*.*"
            rm -rf "${{ env.SPM_IG_LIST_KIT_PUBLIC_HEADERS_PATH }}/*.*"
            rm -rf "${{ env.SPM_IG_LIST_KIT_SOURCES_PATH }}/*.*"

      - name: Regenerate SPM layout
        run: sh scripts/generate_spm_sources_layout.sh

      - name: Clean project's ${{ env.PROJECT_NAME }}
        run: |
          rm -rf "${{ env.PROJECT_NAME }}"

      - name: Verify IGListKit can be build using Package.swift which was generated by 'scripts/generate_spm_sources_layout.sh'
        run: xcodebuild -scheme "IGListKit" build -destination "${{ env.IOS_DESTINATION }}" | xcpretty

  SPM-build-from-Package:
    name: Verify SPM build by invoking `xcodebuild` on Package.swift
    runs-on: macos-14
    env:
      DEVELOPER_DIR: /Applications/Xcode.app
      PROJECT_NAME: IGListKit.xcodeproj
      IOS_DESTINATION: "platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.2"
    strategy:
      matrix:
        schemeName: ["IGListDiffKit",
                      "IGListKit",
                      "IGListSwiftKit"]
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Clean project's ${{ env.PROJECT_NAME }}
        run: |
          rm -rf "${{ env.PROJECT_NAME }}"

      - name: Run ${{ matrix.schemeName}} using Package.swift
        run: xcodebuild -scheme "${{ matrix.schemeName}}" build -destination "${{ env.IOS_DESTINATION }}" | xcpretty

  Carthage-XCFramework:
    name: Verify Carthage build XCFramework
    runs-on: macos-14
    env:
      DEVELOPER_DIR: /Applications/Xcode.app
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Carthage build framework
        run: carthage build --no-skip-current --use-xcframeworks

  Build-Examples:
    name: Build Examples and UI tests.
    runs-on: macos-14
    env:
      DEVELOPER_DIR: /Applications/Xcode.app
      IOS_EXAMPLE_XCODEPROJ: Examples/Examples-iOS/IGListKitExamples.xcodeproj
      TVOS_EXAMPLE_XCODEPROJ: Examples/Examples-tvOS/IGListKitExamples.xcodeproj
      MACOS_EXAMPLE_XCODEPROJ: Examples/Examples-macOS/IGListKitExamples.xcodeproj
      EXAMPLE_SCHEME: IGListKitExamples
    strategy:
      matrix:
        iosDestination: ["platform=iOS Simulator,name=iPhone 16 Pro Max,OS=18.2"]
        tvOSDestination: ["platform=tvOS Simulator,name=Apple TV 4K (3rd generation)"]
        macOSDestination: ["platform=macOS"]
        macCatalystDestination: ["platform=macOS,variant=Mac Catalyst"]
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Cache RubyGems
        uses: actions/cache@v3
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Install ruby gems.
        run: bundle install

      - name: Preboot iOS Simulator
        uses: futureware-tech/simulator-action@v2
        with:
          model: 'iPhone 16 Pro Max'
          os_version: '=18.2'

      - name: Build iOS Example - ${{ matrix.iosDestination }}
        run: |
          set -o pipefail
          xcodebuild build build-for-testing -project "${{ env.IOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.iosDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c

      - name: Run iOS Example's UI Tests - ${{ matrix.iosDestination }}
        run: |
          set -o pipefail
          xcodebuild build test -project "${{ env.IOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.iosDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c

      - name: Build tvOS Example - ${{ matrix.tvOSDestination }}
        run: |
          set -o pipefail
          xcodebuild build -project "${{ env.TVOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.tvOSDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c

      - name: Build macOS Example - ${{ matrix.macOSDestination }}
        run: |
          set -o pipefail
          xcodebuild build -project "${{ env.MACOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.macOSDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c

      - name: Build Mac Catalyst Example - ${{ matrix.macCatalystDestination }}
        run: |
          set -o pipefail
          xcodebuild build -project "${{ env.IOS_EXAMPLE_XCODEPROJ }}" -scheme "${{ env.EXAMPLE_SCHEME }}" -destination "${{ matrix.macCatalystDestination }}" -configuration Debug ONLY_ACTIVE_ARCH=YES CODE_SIGNING_REQUIRED=NO | bundle exec xcpretty -c

  Danger:
    name: Run Danger
    if: github.event_name == 'pull_request'
    runs-on: macos-14
    env:
      DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Cache RubyGems
        uses: actions/cache@v3
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Install ruby gems.
        run: bundle install

      - name: Run Danger
        run: bundle exec danger --verbose



================================================
FILE: .gitignore
================================================
.DS_Store

Podfile.lock
Gemfile.lock

# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## Build generated
build/
DerivedData/

## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/

## Other
*.moved-aside
*.xcuserstate

## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM

## Docs
docs/docsets/

## Playgrounds
timeline.xctimeline
playground.xcworkspace

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
.build/

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

Pods/

# Add this line if you want to avoid checking in source code from the Xcode workspace
*.xcworkspace

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

# Bundler
.bundle
vendor

# Jetbrains
.idea


================================================
FILE: .slather.yml
================================================
ci_service: github
coverage_service: coveralls
xcodeproj: IGListKit.xcodeproj
workspace: IGListKit.xcworkspace
scheme: IGListKit
source_directory: Source
ignore:
  - ../**/*/Xcode*
  - Tests/*


================================================
FILE: .swiftlint.yml
================================================
included:
  - Examples
  - Source/IGListSwiftKit

excluded:
  - Pods

opt_in_rules:
  - empty_count
  - number_separator
  - operator_usage_whitespace
  - sorted_imports
  - vertical_parameter_alignment_on_call
  - overridden_super_call

disabled_rules:
  - force_unwrapping
  - comma
  - line_length

force_cast: warning
force_try: warning

weak_delegate: error

type_body_length:
  warning: 300
  error: 400

file_length:
  warning: 500
  error: 1200

type_name:
  min_length: 4
  max_length:
    warning: 40
    error: 50
  excluded: iPhone

identifier_name:
  min_length:
    error: 4
  excluded:
    - id
    - url
    - URL
    - pk
    - day
    - map
    - row
    - nib
    - GlobalAPIKey
    - to
    - obj
    - str
    - set

reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji)


================================================
FILE: CHANGELOG.md
================================================
# CHANGELOG

The changelog for `IGListKit`. Also see the [releases](https://github.com/instagram/IGListKit/releases) on GitHub.

5.3.0 (Upcoming Release)
-----

5.2.0
-----

### Enhancements

- Added a more defensive check for NaN values in item bounds when applying layout attributes in `-[IGListCollectionViewLayout layoutAttributesForItemAtIndexPath:]`. Minqi Ma [(358fe894)](https://github.com/Instagram/IGListKit/commit/358fe894f2c66a14ac1eda7ba09a2de158373cd5)

- Improved assertion details in `IGListAdapter+UICollectionView.m`. [Maxime Ollivier](https://github.com/maxolls)  [(7240131c)](https://github.com/Instagram/IGListKit/commit/7240131ceaa7784bfed60fdb9a623e3b7f4cdf5b)

- Formalized assertions that `IGListAdapterDelegateAnnouncer` is main-thread confined. Andrew Cuneo [(7dddb0d4)](https://github.com/Instagram/IGListKit/commit/7dddb0d4c83c14a3cade15a24a9df5b61f7a6836)

### Fixes

- An `EXC_BAD_ACCESS` crash in `IGListSectionMap.m` during `IGListAdapter` deallocation. [Hoà V. DINH](https://github.com/dinhvh) [(d1ddab8e)](https://github.com/Instagram/IGListKit/commit/d1ddab8e20fe8b3effc70dc878697e0f421f9a25)

- A crash where an index value provided to `-[IGListBindingSectionController sizeForItemAtIndex:]` was out of bounds. Kaur Ishnoor [(0a0b11bd)](https://github.com/Instagram/IGListKit/commit/0a0b11bdc81d96aa6525d558715bc46d91393711)

5.1.0
-----

### Breaking Changes

- Added methods to the `IGListAdapterDelegate` to include callback methods for any time a cell will appear or did disappear from the screen.  This can be used in conjunction with the `IGListAdapterDelegateAnnouncer` to listen globally for cell lifecycle events.  Any implementer of `IGListAdapterDelegate` must update to include these methods. [Jesse Seidman](https://github.com/jseidman95) [(fa50aa1c)](https://github.com/Instagram/IGListKit/commit/fa50aa1cf1be85940787e211d23eb5e7873dbf24), [(d1d6f9d5)](https://github.com/Instagram/IGListKit/commit/d1d6f9d52caef89efd11444161ac341266d36ccf), [(03049f74)](https://github.com/Instagram/IGListKit/commit/03049f742f46a6ac28abedd249d176cac4694990)

- Added `willCrash` delegate methods in order to capture incoming crashes in IGListKit for analysis. Any implementer of `IGListAdapterUpdaterDelegate` and/or `IGListUpdatingDelegate` must update to include these methods. [Hoà V. DINH](https://github.com/dinhvh) [(da1050ef)](https://github.com/Instagram/IGListKit/commit/da1050ef397c9cf38e88ac047196fe53fe6febb0)

### Enhancements

- Replaced CocoaPods with SPM as the new dependency manager of `IGListKit.xcodeproj` when running unit tests. [Tim Oliver](https://github.com/timoliver) [(2964f066)](https://github.com/Instagram/IGListKit/commit/2964f066a3b0ad533f2eeda71096caeb0b54500a)

- Added handling for new collection view cell dequeue behavior in iOS 18 [Maxime Ollivier](https://github.com/maxolls) [(4bad7d52)](https://github.com/Instagram/IGListKit/commit/4bad7d52604c695e48c0c161fed631aad8511449)

- Added support for Swift Concurrency [Mark Davis](https://instagram.com/m4rk) [(0ec2d52)](https://github.com/Instagram/IGListKit/commit/0ec2d526f35374dc0366024f8bb62aac4db1fd8d)

- Exposed an option to disable layout cache invalidation when new items are inserted [Constantine Fry](https://github.com/constantine-fry) [(700905e)](https://github.com/Instagram/IGListKit/commit/700905e628bf56abebce5bbdb0698ecade3c9842)

- Exposed `IGListCollectionViewLayoutInvalidationContext` as a public interface [(1560956)](https://github.com/Instagram/IGListKit/commit/1560956da3ce27e1816c641541dbdc616cf5ef56)

- Annotated main API classes with `NS_SWIFT_UI_ACTOR` in preparation of moving to Swift 6 [Cory Wilhite](https://github.com/corywilhite) [(a28d835)](https://github.com/Instagram/IGListKit/commit/a28d835b739af5136841622854b276d07cda7852)

- Added `autoDeselectEnabled` on `IGListAdapter` to free each section-controller from having to do this and avoid bugs [Maxime Ollivier](https://github.com/maxolls) [(fec6b0e)](https://github.com/Instagram/IGListKit/commit/fec6b0ef0f4a0224519b868cb51600ad3fdf6923)

- Added `associatedListAdapters` as a property of `UIViewController` to track `IGListAdapter` instances bound to that view controller. [Maxime Ollivier](https://github.com/maxolls) [(9c0ef52)](https://github.com/Instagram/IGListKit/commit/9c0ef5271583fadaa10fda6340794c20bcf609b2)

- Added assert when a section's `diffIdentifier` changed before an update starts, which could manifest in a few different crashes [Maxime Ollivier](https://github.com/maxolls) [(64ba471)](https://github.com/Instagram/IGListKit/commit/64ba4712012f074acbafa3fee05aefb28fa06fd2)

- Added support for iOS 13 Context Menus with `contextMenuConfigurationForItemAt` method. [Jérôme B.](https://github.com/jeromeboursier) [(23daf6d)](https://github.com/Instagram/IGListKit/commit/23daf6de7290198b775062d04906ba3019519ff0).

### Fixes

- A crash that could periodically occur when collection view layout attributes were `nil` [(6e91299)](https://github.com/Instagram/IGListKit/commit/6e9129978e0e3537aec53eea2d6909e45fe057f9)

- A crash that could occur when reloading the same cell index multiple times [Maxime Ollivier](https://github.com/maxolls) [(0c25779)](https://github.com/Instagram/IGListKit/commit/0c257795e4a6e448fb76b5f15ebc83a1afcbd272)

- A crash in `IGListCollectionViewLayout` that could occur if a nil `indexPath` value was provided [(5ee2207)](https://github.com/Instagram/IGListKit/commit/5ee22079822ef30d05366d58173b09e238b6e44b)

5.0.0
-----
### Breaking Changes

- Changed iOS deployment target to 11.0 and macOS deployment target to 10.13 [Kent Sutherland](https://github.com/ksuther) [(#1573)](https://github.com/Instagram/IGListKit/pull/1573)

- Removed unneeded diffing functions `IGListDiffExperiment(...)` and `IGListDiffPathsExperiment(...)`. [Maxime Ollivier](https://github.com/maxolls) [(254c041)](https://github.com/Instagram/IGListKit/commit/254c04196a6b906a155d8a1dd670c720500bed6c)

- `ListSectionController.collectionContext` and `ListGenericSectionController.object` are now implicitly-unwrapped optionals in Swift. [Nate Stedman](https://github.com/natestedman) [(a6526ce)](https://github.com/Instagram/IGListKit/commit/a6526ce097fe38de85459cd6a34d948ec8440db7)

- The argument of `IGListGenericSectionController`'s `-didUpdateToObject:` is now generic, not `id`. [Nate Stedman](https://github.com/natestedman) [(a6526ce)](https://github.com/Instagram/IGListKit/commit/a6526ce097fe38de85459cd6a34d948ec8440db7)

- Updated  `IGListUpdatingDelegate`, including a new method to safely perform `[IGListAdapter setDataSource:]` and changes to `-performUpdateWithCollectionViewBlock` that allows section-controllers to be created before the diffing (and therefore use a more accurate `toObjects` array) [Maxime Ollivier](https://github.com/maxolls) [(43af883)](https://github.com/Instagram/IGListKit/commit/43af8838dfdcfc50b8145c56cfecb5f5ed9195a5)

```objc
// OLD
- (void)performUpdateWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
                                 fromObjects:(nullable NSArray<id <IGListDiffable>> *)fromObjects
                              toObjectsBlock:(nullable IGListToObjectBlock)toObjectsBlock
                                    animated:(BOOL)animated
                       objectTransitionBlock:(IGListObjectTransitionBlock)objectTransitionBlock
                                  completion:(nullable IGListUpdatingCompletion)completion;

// NEW
- (void)performUpdateWithCollectionViewBlock:(IGListCollectionViewBlock)collectionViewBlock
                                    animated:(BOOL)animated
                            sectionDataBlock:(IGListTransitionDataBlock)sectionDataBlock
                       applySectionDataBlock:(IGListTransitionDataApplyBlock)applySectionDataBlock
                                  completion:(nullable IGListUpdatingCompletion)completion;

// NEW
- (void)performDataSourceChange:(IGListDataSourceChangeBlock)block;
```

- Removed `allowsBackgroundReloading` from `IGListAdapterUpdater` because it's causing performance issues and other bugs. [Maxime Ollivier](https://github.com/maxolls) [(032e1b0)](https://github.com/Instagram/IGListKit/commit/032e1b0b8367e68ef3015f0dc7dfe2f3ff2bae0c)

- Introducing `allowsBackgroundDiffing` on `IGListAdapterUpdater`! This property lets the updater perform the diffing on a background thread. Originally introduced by Ryan Nystrom a while back. [Maxime Ollivier](https://github.com/maxolls) [(9a11f6)](https://github.com/Instagram/IGListKit/commit/9a11f6b55f02a8a89494035fb17203655e454404)

- Updated `scrollToObject:` method in `IGListAdapter` to include a new parameter `additionalOffset` to handle shifting the final scroll position by some vertical or horizontal offset depending on the scroll direction. This allows the object to be shown at the correct position when it is scrolled to in a list with sticky headers. [Anna Tang](https://www.instagram.com/anna.likesfood/) [(f2166c3)](https://github.com/Instagram/IGListKit/commit/f2166c358b3ed0fb3e9dd55d2bed9b7fe7a6a05e)

```objc
// OLD
- (void)scrollToObject:(id)object
    supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
       scrollDirection:(UICollectionViewScrollDirection)scrollDirection
        scrollPosition:(UICollectionViewScrollPosition)scrollPosition
              animated:(BOOL)animated;

// NEW
- (void)scrollToObject:(id)object
    supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
       scrollDirection:(UICollectionViewScrollDirection)scrollDirection
        scrollPosition:(UICollectionViewScrollPosition)scrollPosition
      additionalOffset:(CGPoint)additionalOffset
              animated:(BOOL)animated;
```

- Unshipped the `IGListExperimentSkipViewSectionControllerMap` experiment as it was no longer being used. [Maxime Ollivier](https://github.com/maxolls) [(99e24af)](https://github.com/Instagram/IGListKit/commit/99e24afbf872c0d858291084cfa45243f0c9a448)

- Unshipped the `IGListExperimentSkipPerformUpdateIfPossible` experiment since it wasn't considered safe enough. [Maxime Ollivier](https://github.com/maxolls) [(b3a22ad)](https://github.com/Instagram/IGListKit/commit/b3a22ad554995b3a869bb1b75369108e65bd867e)

### Enhancements

- Added `traitCollection` property to `IGListAdapter` in order to access the current trait collection of the underlying collection view. [Sash Zats](https://github.com/zats) [(53a96a9)](https://github.com/Instagram/IGListKit/commit/53a96a9896732ffeb2683953aa6bd23642743ec8)

- Added `viewForSupplementaryElementOfKind:atIndex:sectionController:` to `IGListAdapter`. [ryanmathews](https://www.instagram.com/_rmathews_/) [(c708a10)](https://github.com/Instagram/IGListKit/commit/c708a10757944f147110a31be661d015e9fc901c)

- Replaced usage of `method_exchangeImplementations` with `class_replaceMethod` for increased performance. [Saagar Jha](https://github.com/saagarjha) [(#1583)](https://github.com/Instagram/IGListKit/pull/1583)

- Added `shouldDeselectItemAtIndex:` to `IGListSectionController`. [bladeofky](https://github.com/bladeofky) [(b22a10e)](https://github.com/Instagram/IGListKit/commit/b22a10e47ffa87c79993ea19db7b52605e83ebbf)

- Added `shouldSelectItemAtIndex:` to `IGListSectionController`. [dirtmelon](https://github.com/dirtmelon) [(#1479)](https://github.com/Instagram/IGListKit/pull/1479)

- Added [Mac Catalyst](https://developer.apple.com/mac-catalyst/) support. [Petro Rovenskyy](https://github.com/3a4oT/) [(#1487)](https://github.com/Instagram/IGListKit/pull/1487)

- Introduce `IGListSwiftKit`, with Swift refinements for `dequeueReusableCellOfClass` methods. [Koen Punt](https://github.com/koenpunt) [(#1388)](https://github.com/Instagram/IGListKit/pull/1388).

- Added `APPLICATION_EXTENSION_API_ONLY` support for `IGListDiffKit` [Peter Meyers](https://github.com/pm-dev) [(#1422)](https://github.com/Instagram/IGListKit/pull/1422)

- Improved performance by deferring requesting objects from the `IGListAdapterDataSource` until just before diffing is executed. If n updates are coalesced into one, this results in just a single request for objects from the data source. Shipped with experiment `IGListExperimentDeferredToObjectCreation` from Ryan Nystrom.  [Maxime Ollivier](https://github.com/maxolls) [(7fc4384)](https://github.com/Instagram/IGListKit/commit/7fc4384a786968027f529ad24b8d821f671d25af)

- Improved performance by using `reloadData` when there are too many diffing updates. Shipped with experiment `IGListExperimentReloadDataFallback` from Ryan Nystrom. [Maxime Ollivier](https://github.com/maxolls) [(86ecc60)](https://github.com/Instagram/IGListKit/commit/86ecc600856b4199f8a31359140753955f02b5a4)

- Small performance improvement by replacing `NSSet` with `NSArray` during the data update to avoid unnecessary hashing, especially when dealing with lots of large objects with non trivial hashes. [Maxime Ollivier](https://github.com/maxolls) [(c0cf10d)](https://github.com/Instagram/IGListKit/commit/c0cf10d84c0d41b5c02af3a9f3268e438b8e1e77)

- Lazy initialize the `-emptyViewForListAdapter:` [Maxime Ollivier](https://github.com/maxolls) [(29d4640)](https://github.com/Instagram/IGListKit/commit/29d464099782813113246da47cb9c7bf4676a311)

- Updated  `IGListAdapterUpdater` to be safer, more performant, and better organized! [Maxime Ollivier](https://github.com/maxolls) [(247e7ca)](https://github.com/Instagram/IGListKit/commit/247e7cac6547d52dbabf0c6fdcb7fa38b00d0e0f)
   - Safely handles `[IGListAdapter setDataSource:]` by also invalidating the `UICollectionView` data.
   - Safely handles `[IGListAdapter setCollectionView:]` by cancelling on-going transactions.
   - Safely handles returning nil `IGListSectionController` from `IGListAdapterDataSource` by dumping objects that don't have a controller before the diffing.
   - Checks that the `UICollectionView` section count matches the `IGListAdapter` before committing the update, otherwise fallback to a reload.
   - Schedules an update block (`dispatch_async`) only when needed, instead of scheduling on every single call to `-performUpdateWithCollectionViewBlock`.
   - Wraps each update in a `transaction` that can be easily cancelled.
   - Uses methods instead of blocks to make the callstack easier to read in crash reports.
   - Unblocks `IGListExperimentBackgroundDiffing`


- The `IGListExperimentFixCrashOnReloadObjects` experiment succeeded and has officially been implemented into IGListKit. [Maxime Ollivier](https://github.com/maxolls) [(99e24af)](https://github.com/Instagram/IGListKit/commit/99e24afbf872c0d858291084cfa45243f0c9a448)

- Added `IGListExperimentKeepPointerToCollectionViewDataSource` experiment as a potential solution for certain crashes being periodically observed.

- Added `IGListExperimentDisableAnimationOnUpdates` experiment to optionally disable update animations in `IGListAdapter` instances. [(eeb5208)](https://github.com/Instagram/IGListKit/commit/eeb5208911fe340b39d2cc3231d1cd59df16e215)

### Fixes

- Don't crash if you use `IGListSectionController` without a subclass [Maxime Ollivier](https://github.com/maxolls) [(6ea2b91)](https://github.com/Instagram/IGListKit/commit/6ea2b91150040911bcbe4f98201e36035e26e47f)

- Testing crash fix when calling `-[IGListAdapter reloadObjects ...]` during an update [Maxime Ollivier](https://github.com/maxolls) [(cd3f84f)](https://github.com/Instagram/IGListKit/commit/cd3f84f22709dc6bd0153476372cade8167b9513)

- Repaired Swift Package Manager support. [Petro Rovenskyy](https://github.com/3a4oT/) [(#1487)](https://github.com/Instagram/IGListKit/pull/1487)

- `IGListCollectionViewLayout` should get the section/index counts via `UICollectionView` to stay in sync, instead of the `dataSource` [Maxime Ollivier](https://github.com/maxolls) [(677ce77)](https://github.com/Instagram/IGListKit/commit/677ce77ecad11850f61436681ee1d04a5e67e96a)

- Remove `[collectionView layoutIfNeeded]` before scrolling in `[IGListAdapter scrollToObject...]` to avoid creating off-screen cells. [Maxime Ollivier](https://github.com/maxolls) [(ea03bc9)](https://github.com/Instagram/IGListKit/commit/ea03bc959dcfdc5937655ca471135f874980f0ad)

- Remove `[collectionView layoutIfNeeded]` before updating in `[IGListAdapterUpdater performBatchUpdates...]` to fix occasional glitches. [Maxime Ollivier](https://github.com/maxolls) [(aca18c7)](https://github.com/Instagram/IGListKit/commit/aca18c747009c5d2c3825cf0af1ea1d214afba0c)

- Fixed `IGListAdapterUpdaterDelegate` by 1) calling `willReloadDataWithCollectionView` on fallback reloads and 2) making sure `willPerformBatchUpdatesWithCollectionView` is only called when performing a batch update. [Maxime Ollivier](https://github.com/maxolls) [(29bf582)](https://github.com/Instagram/IGListKit/commit/29bf582f479ddf6beb118abc83ba7a8ea87543b0)

- Fixed missing update when calling `performUpdatesAnimated` multiple times quickly and using the `reloadDataFallback()`. [Maxime Ollivier](https://github.com/maxolls) [(a70d2d7)](https://github.com/Instagram/IGListKit/commit/a70d2d70ae8975af5b00f93ae596589b42017c38)

- Request the `UICollectionView` until just-before we update. This way if the `UICollectionView` is changed between update-queue and execution, we guarantee the update is performed on the correct view. Ship with experiment `IGListExperimentGetCollectionViewAtUpdate` from Ryan Nystrom. [Maxime Ollivier](https://github.com/maxolls) [(34c935c)](https://github.com/Instagram/IGListKit/commit/34c935c1a5fee83283beece8f1c6b3d6344f275d)

- Fixed unsigned integer overflow handling in `IGListBatchUpdateData` [Jason Hsu](https://github.com/tuoxie007) [(#1299)](https://github.com/Instagram/IGListKit/pull/1299)

- Fixed when collection views wouldn't recalculate its layout when its bound changes. [Sash Zats](https://github.com/zats) [(d220f8a)](https://github.com/Instagram/IGListKit/commit/d220f8a73fa91fb8444398992b2667f24a38b7a7)

- Fixed when calling `invalidateLayout` on `IGListCollectionViewLayout` wouldn't perform layout recalculation. [Tim Oliver](https://github.com/timoliver) [(ffd51e6)](https://github.com/Instagram/IGListKit/commit/ffd51e6235c761b14c52ac657c69dd52ee7b321f)

4.0.0
-----

### Breaking Changes

- Added Swift annotation name to `IGListAdapterDelegate` which removes `IG` prefix. The new name for Swift clients is `ListAdapterDelegate`. [Andrea Antonioni](https://github.com/andreaantonioni) [(#1116)](https://github.com/Instagram/IGListKit/pull/1116)

- Remove support for iOS 8 [Ian Perry](https://github.com/iperry90) [(#1381)](https://github.com/Instagram/IGListKit/pull/1381)

- `IGListKit` has been split into `IGListKit` and `IGListDiffKit` for Xcode and Carthage builds. Cocoapods continues to use an all-inclusive `IGListKit` podspec. [Nate Stedman](https://github.com/natestedman) [(#1377)](https://github.com/Instagram/IGListKit/pull/1377)

- Remove `coalescanceTime` from IGListAdapterUpdate, since it increase crash rate. [Zhisheng Huang](https://github.com/lorixx) [(2f76e8c)](https://github.com/Instagram/IGListKit/commit/2f76e8ce684bf7cea75ee52f25d4ea0af3e0081b)

- All `IGListBindingSectionControllerSelectionDelegate` methods are now required. [Bofei Zhu](https://github.com/zhubofei) [(#1186)](https://github.com/Instagram/IGListKit/pull/1186)

- Renamed `[IGListAdapterUpdatingDelegate listAdapterUpdater:willPerformBatchUpdatesWithCollectionView:]` to `[IGListAdapterUpdatingDelegate listAdapterUpdater:willPerformBatchUpdatesWithCollectionView:fromObjects:toObjects:listIndexSetResult:]` to include more supporting info on updated objects. [Jeremy Cohen](https://github.com/jeremycohen) [(b200dda)](https://github.com/Instagram/IGListKit/commit/b200ddacf59547641d77e31d313566c78944a67b)

- Renamed `[IGListAdapterUpdatingDelegatelistAdapterUpdater:collectionView:willCrashWithException:fromObjects:toObjects:updates:]` to `[ IGListAdapterUpdatingDelegatelistAdapterUpdater:collectionView:willCrashWithException:fromObjects:toObjects:diffResult:updates:]` to include diff result info. [Zhisheng Huang](https://github.com/lorixx) [(039e77e)](https://github.com/Instagram/IGListKit/commit/039e77e3593251c8711497f76ab25857d641ecee)

- Remove `IGListStackedSectionController`. [Hanton Yang](https://github.com/hanton) [(#1355)](https://github.com/Instagram/IGListKit/pull/1355)

### Enhancements

- Added `IGListCollectionScrollingTraits` for exposing `UICollectionView` scrolling traits to section controllers via `IGListCollectionContext`. [Adam Stern](https://github.com/adamastern) [(b4c8ea1)](https://github.com/Instagram/IGListKit/commit/b4c8ea180f3bbda8b7995da758fbec58bf7214a8)

-  `IGListBindingSectionController` no longer asserts when reloading the entire section. A warning message is now logged if the entire section is going to be reloaded. [Jeff Bailey](https://github.com/jeffbailey) [(#1213)](https://github.com/Instagram/IGListKit/pull/1213)

- Added `preferItemReloadsForSectionReloads` in IGListAdapterUpdater so that the item updates are invoked with the proper collectionView animation, instead of using the delete+insert section operation when the number of items is unchanged. [Zhisheng Huang](https://github.com/lorixx) [(f699ea0)](https://github.com/Instagram/IGListKit/commit/f699ea0e17a8cc6335285dc9f86fb80a0ad49700)

- Created `IGListAdapterPerformanceDelegate` for IGListAdapter to be able to measure how long some operations take across all section controllers. For example, how long it takes to dequeue a cell. [Maxime Ollivier](https://github.com/maxoll) [(4662454)](https://github.com/Instagram/IGListKit/commit/4662454c4aedbc5d3bed0cb386f2ef93de40ba51)

- Update CocoaPods integration to use the CocoaPods specs CDN [Koen Punt](https://github.com/koenpunt) [(#1386)](https://github.com/Instagram/IGListKit/pull/1386)

- Remove useless system version code [Kinarobin](https://github.com/kinarobin) [(#1386)](https://github.com/Instagram/IGListKit/pull/1396)

### Fixes

- Fixed bug with layouts inconsistency in `updateAnimated:completion` of IGListBindingSectionController. [Qinghua Hong](https://github.com/qhhonx) [(#1285)](https://github.com/Instagram/IGListKit/pull/1285)

- Fixed bug with `-[IGListAdapter scrollToObject:supplementaryKinds:scrollDirection:scrollPosition:animated:]` where the content inset(bottom/right) of the collection view was incorrectly being applied to the final offset and was inconsistent with the content inset(top/left) of the collection view being applied. [Qinghua Hong](https://github.com/qhhonx) [(#1284)](https://github.com/Instagram/IGListKit/pull/1284)

- Fixed crash when the data source is nil before calling `-[IGListAdapterUpdater performUpdateWithCollectionViewBlock:fromObjects:toObjectsBlock:animated:objectTransitionBlock:completion:]`. [Zhisheng Huang](https://github.com/lorixx) [(6cdd112)](https://github.com/Instagram/IGListKit/commit/6cdd112790f13a683d3e061a7646f2c3549cc4dd)

- Experimental fix to get the `UICollectionView` for batch updating immediately before applying the update. [Ryan Nystrom](https://github.com/rnystrom) [(583efb9)](https://github.com/Instagram/IGListKit/commit/583efb936b0ba4d8beac0678b145aa5aff8ac12b)

- Fixed bug with `IGListDiff.mm` where arrays of `NSIndexPath`, instead of `NSIndexPath`, were incorrectly set as objects for the IndexPathMaps. [Bofei Zhu](https://github.com/zhubofei) [(#1205)](https://github.com/Instagram/IGListKit/pull/1205)

- `[IGListAdapterUpdater performBatchUpdatesWithCollectionViewBlock:]` and `[IGListAdapterUpdater performReloadDataWithCollectionViewBlock:]` clean state and run completion blocks if their `UICollectionView` is nil. [Brandon Darin](https://github.com/jbd1030) [(290d592)](https://github.com/Instagram/IGListKit/commit/290d592983713c3ef82eb4950ba773a0059563a2)

- Ensuring view models with duplicate diff identifiers are removed when view models are first requested by `IGListBindingSectionController` [Adam Stern](https://github.com/adamastern) [(a1ee4c1)](https://github.com/Instagram/IGListKit/commit/a1ee4c19f7a6cbd9899dba82deb5fb3ece669e9c)

- Fixed `[IGListAdapterUpdater reloadItemInCollectionView:fromIndexPath:toIndexPath:]` does not call delegate when not inside a batch update. [Bofei Zhu](https://github.com/zhubofei) [(#1211)](https://github.com/Instagram/IGListKit/pull/1211)

- Log instead of assert for duplicate diff identifiers to make code testable. [Adam Stern](https://github.com/adamastern) [(bee2178)](https://github.com/Instagram/IGListKit/commit/bee2178443ffcaff1d9135c4e094f74240433a62)

- Removed `nibName` argument from `IGListReusableViewIdentifier`. [Trung Duc](https://github.com/trungducc) [(#1223)](https://github.com/Instagram/IGListKit/issues/1223)

- Fixed crash when using `-[IGListCollectionContext dequeueReusableCellOfClass:withReuseIdentifier:forSectionController:atIndex:]` [Jeremy Lawrence](https://github.com/ziewvater) [(3b19cfb)](https://github.com/Instagram/IGListKit/commit/3b19cfb9d742d1fd97540bd8cf42c3552ab47de9)

- Added missing method override to `IGListBindingSectionController` that updates the internal `viewModels` array after moving a cell. [Dennis Müller](https://github.com/d3mueller) [(#1262)](https://github.com/Instagram/IGListKit/issues/1262)

- Fixed logic flaw in `[IGListCollectionViewLayout shouldInvalidateLayoutForBoundsChange:]`. [Allen Hsu](https://github.com/allenhsu) [(#1236)](https://github.com/Instagram/IGListKit/pull/1236)

- Fixed crash when calling `[UICollectionView layoutAttributesForSupplementaryElementOfKind...]` with `IGListCollectionViewLayout` and the section controller doesn't actually return a supplementary view [Maxime Ollivier](https://github.com/maxolls) [(cddb297)](https://github.com/Instagram/IGListKit/commit/cddb29799c5393f3c1a1ab7e9c072208e8c23225)

- Added `IGListExperimentAvoidLayoutOnScrollToObject` to avoid creating off-screen cells when calling `[IGListAdapter scrollToObject ...]`. [Maxime Ollivier](https://github.com/maxolls) [(6faddd9)](https://github.com/Instagram/IGListKit/commit/6faddd99c95428cf42bb38684464b458ef1455c0)

- Added `IGListExperimentFixIndexPathImbalance` to test fixing a crash when inserting and deleting the same NSIndexPath multiple times. [Maxime Ollivier](https://github.com/maxolls) [(7824698)](https://github.com/Instagram/IGListKit/commit/78246986108e7caf73111fe784057cc107ee67f1)

3.4.0
-----

### Enhancements

- Relicensed IGListKit to MIT. [Ryan Nystrom](https://github.com/rnystrom) [(000bc36)](https://github.com/Instagram/IGListKit/commit/000bc3691909f50649a5dfb098a5f2102c86385b)

- Experimental performance improvement from deferring `-[IGListAdapterDataSource objectsForListAdapter:]` calls until just before diffing. [Ryan Nystrom](https://github.com/rnystrom) [(3059c5e)](https://github.com/Instagram/IGListKit/commit/3059c5e6f5aeac73f112375d032677ae5f38342a)

3.3.0
-----

### Enhancements

- Add support for UICollectionView's interactive reordering in iOS 9+.  Updates include `-[IGListSectionController canMoveItemAtIndex:]` to enable the behavior, `-[IGListSectionController moveObjectFromIndex:toIndex:]` called when items within a section controller were moved through reordering, `-[IGListAdapterDataSource listAdapter:moveObject:from:to]` called when section controllers themselves were reordered (only possible when all section controllers contain exactly 1 object), and `-[IGListUpdatingDelegate moveSectionInCollectionView:fromIndex:toIndex]` to enable custom updaters to conform to the reordering behavior. The update also includes two new examples `ReorderableSectionController` and `ReorderableStackedViewController` to demonstrate how to enable interactive reordering in your client app. [Jared Verdi](https://github.com/jverdi) [(#976)](https://github.com/Instagram/IGListKit/pull/976)

- 5x improvement to diffing performance when result is only inserts or deletes. [Ryan Nystrom](https://github.com/rnystrom) [(afd2d29)](https://github.com/Instagram/IGListKit/commit/afd2d29eecfac2231d2bcf815c76e844c98d838e)

- Can always show sticky header although section data is empty.  [Marcus Wu](https://github.com/marcuswu0814) [(#1129)](https://github.com/Instagram/IGListKit/pull/1129)

- Added `-[IGListCollectionContext dequeueReusableCellOfClass:withReuseIdentifier:forSectionController:atIndex:]` to allow for registering cells of the same class with different reuse identifiers. [Jeremy Lawrence](https://github.com/Ziewvater) [(f47753e)](https://github.com/Instagram/IGListKit/commit/f47753e3615431f3b079eb3b7900469f9ffdce5b)

### Fixes

- Fixed Xcode 9.3 build errors. [Sho Ikeda](https://github.com/ikesyo) [(#1143)](https://github.com/Instagram/IGListKit/pull/1143)

- Copy objects when retrieving from datasource to prevent modification of models in binding section controller. [Kashish Goel](https://github.com/kashishgoel) [(#1109)](https://github.com/Instagram/IGListKit/pull/1109)

- Fixed footer is sticky when `stickyHeader` is `true` [aelam](https://github.com/aelam) [(#1094)](https://github.com/Instagram/IGListKit/pull/1094)

- Updated IGListCollectionViewLayout to rely on layoutAttributesClass instead of vanilla `UICollectionViewLayoutAttributes` [Cole Potrocky](https://github.com/SirensOfTitan) [#1135](https://github.com/instagram/IGListKit/pull/1135)

- `-[IGListSectionController didSelectItemAtIndex:]` is now called when a `scrollViewDelegate` or `collectionViewDelegate` is set. [Ryan Nystrom](https://github.com/rnystrom) [(#1108)](https://github.com/Instagram/IGListKit/pull/1108)

- Fixed binding section controllers failing to update their cells when the section controller's section changes. [Chrisna Aing](https://github.com/ccrazy88) [(#1144)](https://github.com/Instagram/IGListKit/pull/1144)

- Fixed a bug caused when applying interactive reordering on a single section item while dragging it through the last spot of the collection view and back to some (non-last) target position. [Ofir Gluzman](https://github.com/ofirgluzman) [#1289](https://github.com/Instagram/IGListKit/pull/1289)

3.2.0
-----

### Enhancements

- Added `-[IGListSectionController didHighlightItemAtIndex:]` and `-[IGListSectionController didUnhighlightItemAtIndex:]` APIs to support `UICollectionView` cell highlighting. [Kevin Delannoy](https://github.com/delannoyk) [(#933)](https://github.com/Instagram/IGListKit/pull/933)

- Added `-didDeselectSectionController:withObject:` to `IGListSingleSectionControllerDelegate` [Darren Clark](https://github.com/darrenclark) [(#954)](https://github.com/Instagram/IGListKit/pull/954)

- Added a new listener API to be notified when `IGListAdapter` finishes updating. Add listeners via `-[IGListAdapter addUpdateListener:]` with objects conforming to the new `IGListAdapterUpdateListener` protocol. [Ryan Nystrom](https://github.com/rnystrom) [(5cf01cc)](https://github.com/Instagram/IGListKit/commit/5cf01cc0a7c41d370600df495aff91d1099fa0bc)

- Updated project settings for iOS 11. [Ryan Nystrom](https://github.com/rnystrom) [(#942)](https://github.com/Instagram/IGListKit/pull/942)

- Added support UICollectionElementKindSectionFooter for IGListCollectionViewLayout. [Igor Vasilenko](https://github.com/vasilenkoigor) [(#1017)](https://github.com/Instagram/IGListKit/pull/1017)

- Added experiment to make  `-[IGListAdapter visibleSectionControllers:]` a bit faster. [Maxime Ollivier](https://github.com/maxoll) [(82a2a2e)](https://github.com/Instagram/IGListKit/commit/82a2a2ee18bb6272744fd14c64c8ff2da3a620a6)

- Added support `-[UIScrollView adjustedContentInset]` for iOS 11. [Guoyin Li](https://github.com/yiplee) [(#1020)](https://github.com/Instagram/IGListKit/pull/1020)

- Added new `transitionDelegate` API to give `IGListSectionController`s control to customize initial and final `UICollectionViewLayoutAttribute`s. Includes automatic integration with `IGListCollectionViewLayout`. Sue Suhan Ma [(26924ec)](https://github.com/Instagram/IGListKit/commit/26924ec3b665d37aeed7e28887e4221a7f3501b1)

- Reordered position of intercepted selector in `IGListAdapterProxy`'s `isInterceptedSelector` method to reduce overall consumption of compare. [zhongwuzw](https://github.com/zhongwu) [(#1055)](https://github.com/Instagram/IGListKit/pull/1055)

- Made IGListTransitionDelegate inherited from NSObject. [Igor Vasilenko](https://github.com/vasilenkoigor) [(#1075)](https://github.com/Instagram/IGListKit/pull/1075)

### Fixes

- Duplicate objects for initial data source setup filtered out. [Mikhail Vashlyaev](https://github.com/yemodin) [(#993](https://github.com/Instagram/IGListKit/pull/993)

- Weakly reference the `UICollectionView` in coalescence so that it can be released if the rest of system is destroyed. [Ryan Nystrom](https://github.com/rnystrom) [(d322c2e)](https://github.com/Instagram/IGListKit/commit/d322c2e5ae241141309923da257542f163c07cc6)

- Fix bug with `-[IGListAdapter scrollToObject:supplementaryKinds:scrollDirection:scrollPosition:animated:]` where the content inset of the collection view was incorrectly being applied to the final offset. [Ryan Nystrom](https://github.com/rnystrom) [(b2860c3)](https://github.com/Instagram/IGListKit/commit/b2860c3604f0c452be1d21ab09c771c921786150)

- Avoid crash when invalidating the layout while inside `-[UICollectionView performBatchUpdates:completion:]. [Ryan Nystrom](https://github.com/rnystrom) [(d9a89c9)](https://github.com/Instagram/IGListKit/commit/d9a89c9b00aa1a9537a24d9affb6919f83065f65)

- Duplicate view models in `IGListBindingSectionController` gets filtered out. [Weyert de Boer](https://github.com/weyert) [(#916)](https://github.com/Instagram/IGListKit/pull/916)

- Check object type on lookup to prevent crossing types if different objects collide with their identifiers. [Ryan Nystrom](https://github.com/rnystrom) [(296baf5)](https://github.com/Instagram/IGListKit/commit/296baf5f854f57150ed12ca5bd8d3903db492734)

3.1.1
-----

### Fixes

- Prevent a crash when `IGListBindingSectionControllerDelegate` objects do not implement the optional deselection API. [Ryan Nystrom](https://github.com/rnystrom) [(#921)](https://github.com/Instagram/IGListKit/pull/921)

3.1.0
-----

### Enhancements

- Added debug descriptions for 'IGListBindingSectionController' when printing to lldb via `po [IGListDebugger dump]`. [Candance Smith](https://github.com/candance) [(#856)](https://github.com/Instagram/IGListKit/pull/856)

- Added `-[IGListSectionController didDeselectItemAtIndex:]` API to support default `UICollectionView` cell deselection. [Ryan Nystrom](https://github.com/rnystrom) [(6540f96)](https://github.com/Instagram/IGListKit/commit/6540f960e2e69bd4776e1e1d8c460ff812ba4c07)

- Added `-[IGListCollectionContext selectItemAtIndex:]` Select an item through IGListCollectionContext like `-[IGListCollectionContext deselectItemAtIndex:]`. [Marvin Nazari](https://github.com/MarvinNazari) [(#874)](https://github.com/Instagram/IGListKit/pull/874)

- Added horizontal scrolling support to `IGListCollectionViewLayout`. [Peter Edmonston](https://github.com/edmonston)  [(#857)](https://github.com/Instagram/IGListKit/pull/857)

- Added support for `scrollViewDidEndDecelerating` to `IGListAdapter`. [Phil Larson](https://github.com/plarson) [(#899)](https://github.com/Instagram/IGListKit/pull/899)

- Automatically disable `[UICollectionView isPrefetchingEnabled]` when setting a collection view on an adapter. [Ryan Nystrom](https://github.com/rnystrom) [(#889)](https://github.com/Instagram/IGListKit/pull/889)

### Fixes

- Prevent a crash when update queued immediately after item batch update. [Ryan Nystrom](https://github.com/rnystrom) [(3dc6060)](https://github.com/Instagram/IGListKit/commit/3dc6060a385d9bfcb4fa1f61262ba74776573229)

- Return correct `-[IGListAdapter visibleSectionControllers]` when section has no items, but has supplementary views. [Mani Ghasemlou](https://github.com/manicakes) [(#643)](https://github.com/Instagram/IGListKit/issues/643)

- Call `[CATransaction commit]` before calling completion block in IGListAdapterUpdater to prevent animation issues. [Maxime Ollivier](https://github.com/maxoll) [(6f946b2)](https://github.com/Instagram/IGListKit/commit/6f946b2981d266f823324a366213bd214357bb6d)

- Fix `scrollToObject:supplementaryKinds:...` not scrolling when section is empty but does have supplymentary views. [Gulam Moledina](https://github.com/gmoledina) [(#808)](https://github.com/Instagram/IGListKit/pull/808)

- Better support for non-top positions in `scrollToObject:` API. [Gulam Moledina](https://github.com/gmoledina) [(#861)](https://github.com/Instagram/IGListKit/pull/861)

3.0.0
-----

This release closes the [3.0.0 milestone](https://github.com/Instagram/IGListKit/milestone/3).

### Breaking Changes

- Added Swift annotation names which remove `IG` prefixes from class names, C functions, and other APIs. Note, this only affects Swift clients. [Robert Payne](https://github.com/robertjpayne) [(#593)](https://github.com/Instagram/IGListKit/pull/593)

Example:

```swift
// OLD
class MySectionController : IGListSectionController { ... }

// NEW
class MySectionController : ListSectionController { ... }

// OLD
IGListDiff([], [], .equality)

// NEW
ListDiff(oldArray: [], newArray: [], .equality)

```

- Updated `didSelect` delegate call in `IGListSingleSectionControllerDelegate` to include object. [Sherlouk](https://github.com/Sherlouk) [(#397)](https://github.com/Instagram/IGListKit/pull/397)

```objc
// OLD
- (void)didSelectSingleSectionController:(IGListSingleSectionController *)sectionController;

// NEW
- (void)didSelectSectionController:(IGListSingleSectionController *)sectionController
                        withObject:(id)object;
```

- `IGListUpdatingDelegate` now conforms to `NSObject`, bringing it in line with other framework protocols. [Adlai Holler](https://github.com/Adlai-Holler) [(#435)](https://github.com/Instagram/IGListKit/pull/435)

- Changed `hasChanges` methods in `IGListIndexPathResult` and `IGListIndexSetResult` to read-only properties. [Bofei Zhu](https://github.com/zhubofei) [(#453)](https://github.com/Instagram/IGListKit/pull/453)

- Replaced `IGListGridCollectionViewLayout` with `IGListCollectionViewLayout`. [Ryan Nystrom](https://github.com/rnystrom) ([#482](https://github.com/Instagram/IGListKit/pull/482), [#450](https://github.com/Instagram/IGListKit/pull/450))

- Renamed `IGListAdapterUpdaterDelegate` method to `listAdapterUpdater:didPerformBatchUpdates:collectionView:`. [Vincent Peng](https://github.com/vincent-peng) [(#491)](https://github.com/Instagram/IGListKit/pull/491)

- Moved section controller mutations to `IGListBatchContext`, provided as a parameter when calling `-performBatchAnimated:updates:completion` on a section controller's `collectionContext`. All updates (insert, delete, reload item/section controller) must now be done inside a batch update block. [Ryan Nystrom](https://github.com/rnystrom) [(a15ea08)](https://github.com/Instagram/IGListKit/commit/a15ea0861492c8476bc9b1b92b0d9835814091c7)

```objc
// OLD
[self.collectionContext performBatchAnimated:YES updates:^{
  self.expanded = YES;
  [self.collectionContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:1]];
} completion:nil];

// NEW
[self.collectionContext performBatchAnimated:YES updates:^(id<IGListBatchContext> batchContext) {
  self.expanded = YES;
  [batchContext insertInSectionController:self atIndexes:[NSIndexSet indexSetWithIndex:1]];
} completion:nil];

// OLD
[self.collectionContext reloadSectionController:self];

// NEW
[self.collectionContext performBatchAnimated:YES updates:^(id<IGListBatchContext> batchContext) {
  [batchContext reloadSectionController:self];
} completion:nil];
```

- `-[IGListCollectionContext containerSize]` no longer accounts for the content inset of the collection view when returning a size. If you require that behavior, you can now use `-[IGListCollectionContext insetContainerSize]`. [Ryan Nystrom](https://github.com/rnystrom) [(623ff2a)](https://github.com/Instagram/IGListKit/commit/623ff2a8a85e0e2e8d0331ae3250d67985cd06b6)

- `IGListCollectionView` has been **completely removed** in favor of using plain old `UICollectionView`. See discussion at [#409](https://github.com/Instagram/IGListKit/issues/409) for details. [Jesse Squires](https://github.com/jessesquires) [(2284ce3)](https://github.com/Instagram/IGListKit/commit/2284ce389708f62d99f48ff2ec15644f1ec59537)

- `IGListBatchUpdateData` replaced its `NSSet` properties with `NSArray` instead. [Ryan Nystrom](https://github.com/rnystrom) [(#616)](https://github.com/Instagram/IGListKit/pull/616)

- `IGListUpdatingDelegate` now requires method `-reloadItemInCollectionView:fromIndexPath:toIndexPath:` to handle reloading cells between index paths. [Ryan Nystrom](https://github.com/rnystrom) [(#657)](https://github.com/Instagram/IGListKit/pull/657)

- `-[IGListCollectionContext sectionForSectionController:]` has been removed and replaced with the `NSInteger sectionIndex` property on `IGListSectionController`. [Andrew Monshizadeh](https://github.com/amonshiz) [#671](http://github.com/Instagram/IGListKit/pull/671)

### Enhancements

- Added an initializer on `IGListAdapter` that does not take a `workingRangeSize` and defaults it to 0. [BasThomas](https://github.com/BasThomas) [(#686)](https://github.com/Instagram/IGListKit/pull/686)

- Added `-[IGListAdapter visibleCellsForObject:]` API. [Sherlouk](https://github.com/Sherlouk) [(#442)](https://github.com/Instagram/IGListKit/pull/442)

- Added `-[IGListAdapter sectionControllerForSection:]` API. [Adlai-Holler](https://github.com/Adlai-Holler) [(#477)](https://github.com/Instagram/IGListKit/pull/477)

- You can now manually move items (cells) within a section controller, ex: `[self.collectionContext moveInSectionController:self fromIndex:0 toIndex:1]`. [Ryan Nystrom](https://github.com/rnystrom) [(#418)](https://github.com/Instagram/IGListKit/pull/418)

- Invalidate the layout of a section controller and control the transition with `UIView` animation APIs. [Ryan Nystrom](https://github.com/rnystrom) [(#499)](https://github.com/Instagram/IGListKit/pull/499)

- Added `-[IGListAdapter visibleIndexPathsForSectionController:]` API. [Malecks](https://github.com/Malecks) [(#465)](https://github.com/Instagram/IGListKit/pull/465)

- Added `IGListBindingSectionController` which automatically binds view models to cells and animates updates at the cell level. [Ryan Nystrom](https://github.com/rnystrom) [(#494)](https://github.com/Instagram/IGListKit/pull/494)

- Added `IGListGenericSectionController` to take advantage of Objective-C (and Swift) generics and automatically store strongly-typed references to the object powering your section controller. [Ryan Nystrom](https://github.com/rnystrom) ([301f147](https://github.com/Instagram/IGListKit/commit/301f1471c9a7a802320e07890f5e98f15ada4e2e))

- Added a debug option for IGListKit that you can print to lldb via `po [IGListDebugger dump]`. [Ryan Nystrom](https://github.com/rnystrom) [(#617)](https://github.com/Instagram/IGListKit/pull/617)

### Fixes

- Gracefully handle a `nil` section controller returned by an `IGListAdapterDataSource`. [Ryan Nystrom](https://github.com/rnystrom) [(#488)](https://github.com/Instagram/IGListKit/pull/488)

- Fix bug where emptyView's hidden status is not updated after the number of items is changed with `insertInSectionController:atIndexes:` or related methods. [Peter Edmonston](https://github.com/edmonston) [(#395)](https://github.com/Instagram/IGListKit/pull/395)

- Fix bug where `IGListStackedSectionController`'s children need to know `numberOrItems` before didUpdate is called. [(#348)](https://github.com/Instagram/IGListKit/pull/390)

- Fix bug where `-[UICollectionViewCell ig_setStackedSectionControllerIndex:]` should use `OBJC_ASSOCIATION_COPY_NONATOMIC` for NSNumber. [PhilCai](https://github.com/PhilCai1993) [(#424)](https://github.com/Instagram/IGListKit/pull/426)

- Fix potential bug with suppressing animations (by passing `NO`) during `-[IGListAdapter performUpdatesAnimated: completion:]` where user would see UI glitches/flashing. [Jesse Squires](https://github.com/jessesquires) [(019c990)](https://github.com/Instagram/IGListKit/commit/019c990312eea4203c7388a83b50685d426aa372)

- Fix bug where scroll position would be incorrect in call to `-[IGListAdapter scrollToObject:supplementaryKinds:scrollDirection:scrollPosition:animated:` with scrollDirection/scrollPosition of UICollectionViewScrollDirectionVertical/UICollectionViewScrollPositionCenteredVertically or UICollectionViewScrollDirectionHorizontal/UICollectionViewScrollPositionCenteredHorizontally and with a collection view with nonzero contentInset. [David Yamnitsky](https://github.com/nitsky) [(5cc0fcd)](https://github.com/Instagram/IGListKit/commit/5cc0fcd1d77d6296f57ce1c298301b9881cb4d4a)

- Fix a crash when reusing collection views between embedded `IGListAdapter`s. [Ryan Nystrom](https://github.com/rnystrom) [(#517)](https://github.com/Instagram/IGListKit/pull/517)

- Only collect batch updates when explicitly inside the batch update block, execute them otherwise. Fixes dropped updates. [Ryan Nystrom](https://github.com/rnystrom) [(#494)](https://github.com/Instagram/IGListKit/pull/494)

- Remove objects that return `nil` diff identifiers before updating. [Ryan Nystrom](https://github.com/rnystrom) [(af984ca)](https://github.com/Instagram/IGListKit/commit/af984ca81d4d8c4ba3012be1a45f69670a832ccf)

- Fix a potential crash when a section is moved and deleted at the same time. [Ryan Nystrom](https://github.com/rnystrom) [(#577)](https://github.com/Instagram/IGListKit/pull/577)

- Prevent section controllers and supplementary sources from returning negative sizes that crash `UICollectionViewFlowLayout`. [Ryan Nystrom](https://github.com/rnystrom) [(#583)](https://github.com/Instagram/IGListKit/pull/583)

- Add nullability annotations to a few more headers. [Adlai Holler](https://github.com/Adlai-Holler) [(#626)](https://github.com/Instagram/IGListKit/pull/626)

- Fix a crash when inserting or deleting from the same index within the same batch-update application. [Ryan Nystrom](https://github.com/rnystrom) [(#616)](https://github.com/Instagram/IGListKit/pull/616)

- `IGListSectionType` protocol was removed and its methods were absorted into the `IGListSectionController` base class with default implementations. [Ryan Nystrom](https://github.com/rnystrom) ([3102852](https://github.com/Instagram/IGListKit/commit/3102852ce258274e8727f9094695a9c331e1abf3))

- When setting the collection view on `IGListAdapter`, its layout is now properly invalidated. [Jesse Squires](https://github.com/jessesquires) [(#677)](https://github.com/Instagram/IGListKit/pull/677)

- Fixes a bug when reusing `UICollectionView`s with multiple `IGListAdapter`s in an embedded environment that would accidentally `nil` the `collectionView` property of another adapter. [Ryan Nystrom](https://github.com/rnystrom) [(#721)](https://github.com/Instagram/IGListKit/pull/721)

- Fixes a bug where maintaining a reference to a section controller but not the list adapter in an async block could lead to calling `-[IGListAdapter sectionForSectionController:]` (or checking `-[IGListSectionController sectionIndex]`) and receiving an incorrect value. With the adapter check the value would be 0 because the adapter was `nil` and for the section controller property the value would be the last set index value. [Andrew Monshizadeh](https://github.com/amonshiz) [(#709)](https://github.com/Instagram/IGListKit/issues/709)

2.1.0
-----

This release closes the [2.1.0 milestone](https://github.com/Instagram/IGListKit/milestone/2).

### Enhancements

- Added support for macOS. Note: this is *only* for the Diffing components. There is **no support** for `IGListAdapter`, `IGListSectionController`, and other components at this time. [Guilherme Rambo](https://github.com/insidegui) [(#235)](https://github.com/Instagram/IGListKit/pull/235)

- Added a [macOS example](https://github.com/Instagram/IGListKit/tree/main/Examples/Examples-macOS) project. [Guilherme Rambo](https://github.com/insidegui) [(#337)](https://github.com/Instagram/IGListKit/pull/337)

- Disables `prefetchEnabled` by default on `IGListCollectionView`. [Sven Bacia](https://github.com/svenbacia) [(#323)](https://github.com/Instagram/IGListKit/pull/323)

- Working ranges now work with `IGListStackedSectionController`. [Ryan Nystrom](https://github.com/rnystrom) [(#356)](https://github.com/Instagram/IGListKit/pull/356)

- Added CocoaPods subspec for diffing, `IGListKit/Diffing` and an [installation guide](https://instagram.github.io/IGListKit/installation.html). [Sherlouk](https://github.com/Sherlouk) [(#368)](https://github.com/Instagram/IGListKit/pull/368)

- Added `allowsBackgroundReloading` flag (default `YES`) to `IGListAdapterUpdater` so users can configure this behavior as needed. [Adlai-Holler](https://github.com/Adlai-Holler) [(#375)](https://github.com/Instagram/IGListKit/pull/375)

- `-[IGListAdapter updater]` is now public (read-only). [Adlai-Holler](https://github.com/Adlai-Holler) [(#379)](https://github.com/Instagram/IGListKit/pull/379)

### Fixes

- Avoid `UICollectionView` crashes when queueing a reload and insert/delete on the same item as well as reloading an item in a section that is animating. [Ryan Nystrom](https://github.com/rnystrom) [(#325)](https://github.com/Instagram/IGListKit/pull/325)

- Prevent adapter data source from deallocating after queueing an update. [Ryan Nystrom](https://github.com/rnystrom) [(4cc91a2)](https://github.com/Instagram/IGListKit/commit/4cc91a25c8b262953e4f2d8e5dc78ee15c6265b2)

- Fix out-of-bounds bug when child section controllers in a stack remove cells. [Ryan Nystrom](https://github.com/rnystrom) [(#358)](https://github.com/Instagram/IGListKit/pull/358)

- Fix a grid layout bug when item has full-width and iter-item spacing is not zero. [Bofei Zhu](https://github.com/zhubofei) [(#361)](https://github.com/Instagram/IGListKit/pull/361)

2.0.0
-----

This release closes the [2.0.0 milestone](https://github.com/Instagram/IGListKit/milestone/1?closed=1). We've increased test coverage to 97%. Thanks to the [27 contributors](https://github.com/Instagram/IGListKit/graphs/contributors) who helped with this release!

You can find a [migration guide here](https://instagram.github.io/IGListKit/migration.html) to assist with migrating between 1.0 and 2.0.

### Breaking Changes

- Diff result method on `IGListIndexPathResult` changed. `-resultWithUpdatedMovesAsDeleteInserts` was removed and replaced with `-resultForBatchUpdates` [(b5aa5e3)](https://github.com/Instagram/IGListKit/commit/b5aa5e39002854c947e777c11ae241f67f24d19c)

```
// OLD
- (IGListIndexPathResult *)resultWithUpdatedMovesAsDeleteInserts;

// NEW
- (IGListIndexPathResult *)resultForBatchUpdates;
```

- `IGListDiffable` equality method changed from `isEqual:` to `isEqualToDiffableObject:` [(ab890fc)](https://github.com/Instagram/IGListKit/commit/ab890fc6070f170a2db5a383a6296e62dcf75678)

- The default `NSObject<IGListDiffable>` category was removed and replaced with `NSString<IGListDiffable>` and `NSNumber<IGListDiffable>` categories. All other models will need to conform to `IGListDiffable`. [(3947600)](https://github.com/Instagram/IGListKit/commit/394760081c7c2daa5ae6c18e00cdeaf2b67e22c1)

- Added support for specifying an end position when scrolling. [Bofei Zhu](https://github.com/zhubofei) [(#196)](https://github.com/Instagram/IGListKit/pull/196). The `IGListAdapter` scrolling method changed:

```objc
// OLD
- (void)scrollToObject:(id)object
    supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
       scrollDirection:(UICollectionViewScrollDirection)scrollDirection
              animated:(BOOL)animated;

// NEW
- (void)scrollToObject:(id)object
    supplementaryKinds:(nullable NSArray<NSString *> *)supplementaryKinds
       scrollDirection:(UICollectionViewScrollDirection)scrollDirection
        scrollPosition:(UICollectionViewScrollPosition)scrollPosition
              animated:(BOOL)animated;
```

### Fixes

- Consider supplementary views with display and end-display events. [Ryan Nystrom](https://github.com/rnystrom) [(#470)](https://github.com/Instagram/IGListKit/pull/470)


- Changed `NSUInteger` to `NSInteger` in all public APIs. [Suraya Shivji](https://github.com/surayashivji) [(#200)](https://github.com/Instagram/IGListKit/issues/200)

### Enhancements

- Added support for supplementaryViews created from nibs. [Rawlinxx](https://github.com/rawlinxx) [(#90)](https://github.com/Instagram/IGListKit/pull/90)

- Added support for cells created from nibs. [Sven Bacia](https://github.com/svenbacia) [(#56)](https://github.com/Instagram/IGListKit/pull/56)

- Added an additional initializer for `IGListSingleSectionController` to be able to support single sections created from nibs. An example can be found [here](https://github.com/Instagram/IGListKit/tree/main/Examples/Examples-iOS/IGListKitExamples/ViewControllers/SingleSectionViewController.swift). [(#56)](https://github.com/Instagram/IGListKit/pull/56)

```objc
- (instancetype)initWithNibName:(NSString *)nibName
                         bundle:(nullable NSBundle *)bundle
                 configureBlock:(IGListSingleSectionCellConfigureBlock)configureBlock
                      sizeBlock:(IGListSingleSectionCellSizeBlock)sizeBlock;
```

- Added `-isFirstSection` and `-isLastSection` APIs to `IGListSectionController` [(316fbe2)](https://github.com/Instagram/IGListKit/commit/316fbe2b8b2508b58a0f38387c3a343b9c37e282)

- Added support for cells and supplementaryViews created from storyboard. There's a new required method on the `IGListCollectionContext` protocol to do this. [Bofei Zhu](https://github.com/zhubofei) [(#92)](https://github.com/Instagram/IGListKit/pull/92)

```objc
// IGListCollectionContext
- (__kindof UICollectionViewCell *)dequeueReusableCellFromStoryboardWithIdentifier:(NSString *)identifier
                                                              forSectionController:(IGListSectionController<IGListSectionType> *)sectionController
                                                                           atIndex:(NSInteger)index;
```

- Added `tvOS` support. [Jesse Squires](https://github.com/jessesquires) [(#137)](https://github.com/Instagram/IGListKit/pull/137)

- Added `-[IGListAdapter visibleObjects]` API. [Ryan Nystrom](https://github.com/rnystrom) [(386ae07)](https://github.com/Instagram/IGListKit/commit/386ae0786445c06e1eabf074a4181614332f155f)

- Added `-[IGListAdapter objectForSectionController:]` API. [Ayush Saraswat](https://github.com/saraswatayu) [(#204)](https://github.com/Instagram/IGListKit/pull/204)

- Added `IGListGridCollectionViewLayout`, a section-based grid layout. [Bofei Zhu](https://github.com/zhubofei) [(#225)](https://github.com/Instagram/IGListKit/pull/225)

- Added support for scrolling to an index in a section controller from within that section controller. There's a new required method on the `IGListCollectionContext` protocol to do this. [Jesse Squires](https://github.com/jessesquires) [(e5afb5b)](https://github.com/Instagram/IGListKit/commit/e5afb5b4d0cfc70a2736b02279b6bc239ddf1e5d)

```objc
// IGListCollectionContext
- (void)scrollToSectionController:(IGListSectionController<IGListSectionType> *)sectionController
                          atIndex:(NSInteger)index
                   scrollPosition:(UICollectionViewScrollPosition)scrollPosition
                         animated:(BOOL)animated;
```

### Fixes

- Fixed `-[IGListAdapter reloadDataWithCompletion:]` not returning early when `collectionView` or `dataSource` is `nil` and `completion` is `nil`. [Ben Asher](https://github.com/benasher44) [(#51)](https://github.com/Instagram/IGListKit/pull/51)

- Prevent `UICollectionView` bug when accessing a cell during working range updates. [Ryan Nystrom](https://github.com/rnystrom) [(#216)](https://github.com/Instagram/IGListKit/pull/216)

- Skip reloading for objects that are not found when calling `-[IGListAdapter reloadObjects:]`. [Ryan Nystrom](https://github.com/rnystrom) [(ca15e29)](https://github.com/Instagram/IGListKit/commit/ca15e29cf1dadc6c396fe8f14f16c27f6a38519c)

- Fixes a crash when a reload is queued for an object that is deleted in the same runloop turn. [Ryan Nystrom](https://github.com/rnystrom) [(7c3d499)](https://github.com/Instagram/IGListKit/commit/7c3d4999ebde36ee4666e5aee99716d1ed1fb2d8)

- Fixed a bug where `IGListStackSectionController` would only set its supplementary source once. [Ryan Nystrom](https://github.com/rnystrom) [(#286)](https://github.com/Instagram/IGListKit/pull/286)

- Fixed a bug where `IGListStackSectionController` passed the wrong section controller for will-drag scroll events. [Ryan Nystrom](https://github.com/rnystrom) [(#286)](https://github.com/Instagram/IGListKit/pull/286)

- Fixed a crash when deselecting a cell through a child section controller in an `IGListStackSectionController`. [Ryan Nystrom](https://github.com/rnystrom) [(#295)](https://github.com/Instagram/IGListKit/pull/295)

### Documentation

- We now have 100% documentation coverage. Docs been refined and clarified. [Jesse Squires](https://github.com/jessesquires) [(#207)](https://github.com/Instagram/IGListKit/pull/207)

- Added new Guides: [Getting Started](https://instagram.github.io/IGListKit/getting-started.html), [Migration](https://instagram.github.io/IGListKit/migration.html)

- Added examples for Today & iMessage extensions. [Sherlouk](https://github.com/Sherlouk) [(#112)](https://github.com/Instagram/IGListKit/pull/112)

- Added `tvOS` example pack. [Sherlouk](https://github.com/Sherlouk) [(#141)](https://github.com/Instagram/IGListKit/pull/141)

1.0.0
-----

Initial release. :tada:


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
  advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
  address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <opensource-conduct@fb.com>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq



================================================
FILE: Dangerfile
================================================
not_declared_trivial = !(github.pr_title.include? "#trivial")
has_source_changes = !git.modified_files.grep(/Source/).empty?

# Make it more obvious that a PR is a work in progress and shouldn't be merged yet
warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]"

# Warn when there is a big PR
warn("Big PR") if git.lines_of_code > 500

# Changelog entries are required for changes to library files
no_changelog_entry = !git.modified_files.include?("CHANGELOG.md")
if has_source_changes && no_changelog_entry && not_declared_trivial && git.lines_of_code > 10
  fail("Any source code changes should have an entry in CHANGELOG.md.")
end

# Milestones are required to track what's included in each release
if has_source_changes && not_declared_trivial
  has_milestone = !github.pr_json['milestone'].nil?
  warn('All pull requests should have a milestone attached, unless marked *#trivial*.', sticky: false) unless has_milestone
end

# Docs are regenerated when releasing
has_doc_changes = !git.modified_files.grep(/docs\//).empty?
has_doc_gen_title = github.pr_title.include? "#docgen"
if has_doc_changes && !has_doc_gen_title
  fail("Docs are regenerated when creating new releases.")
  message("Docs are generated by using [Jazzy](https://github.com/realm/jazzy). If you want to contribute, please update [markdown guides](https://github.com/Instagram/IGListKit/tree/main/Guides)")
end

# Warn if Source files were added or removed but examples are not updated
added_source_files = !git.added_files.grep(/Source/).empty?
deleted_source_files = !git.deleted_files.grep(/Source/).empty?
ios_pods_not_updated = !git.modified_files.include?("Examples/Examples-iOS/Podfile.lock")
macos_pods_not_updated = !git.modified_files.include?("Examples/Examples-macOS/Podfile.lock")
tvos_pods_not_updated = !git.modified_files.include?("Examples/Examples-tvOS/Podfile.lock")
if (added_source_files || deleted_source_files) && (ios_pods_not_updated || macos_pods_not_updated || tvos_pods_not_updated)
  warn("Adding or removing library source files requires updating the examples. Please run `./scripts/pod_setup.sh` from the root directory and commit the changes.")
end

swiftlint.verbose = true
swiftlint.config_file = '.swiftlint.yml'
swiftlint.lint_files(inline_mode: true)


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/AppDelegate.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var isLaunched = false
    var window: UIWindow?

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let demosViewController = DemosViewController()
        let splitViewController = UISplitViewController()
        splitViewController.delegate = self
        splitViewController.viewControllers = [UINavigationController(rootViewController: demosViewController)]
        splitViewController.preferredDisplayMode = .oneBesideSecondary

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = splitViewController
        window?.makeKeyAndVisible()
        UICollectionView.appearance().backgroundColor = UIColor.background

        return true
    }
}

extension AppDelegate: UISplitViewControllerDelegate {
    func splitViewController(_ splitViewController: UISplitViewController,
                             collapseSecondary secondaryViewController: UIViewController,
                             onto primaryViewController: UIViewController) -> Bool {
        // We set up 2 view controllers on launch to enable the split view controller when launching on iPad.
        // However, for iPhone, discard the second view controller so the Demos view controller is visible at launch.
        if !isLaunched {
            isLaunched = true
            return true
        }
        return false
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "AppIcon.png",
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="332-e4-q4q">
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
    </dependencies>
    <scenes>
        <!--Navigation Controller-->
        <scene sceneID="poO-K0-5eC">
            <objects>
                <navigationController id="332-e4-q4q" sceneMemberID="viewController">
                    <simulatedScreenMetrics key="simulatedDestinationMetrics"/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" id="mqI-0B-dj6">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <connections>
                        <segue destination="g8o-Tr-qN9" kind="relationship" relationship="rootViewController" id="o4N-Oy-Tdk"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="JfD-hh-Oex" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-359" y="369"/>
        </scene>
        <!--View Controller-->
        <scene sceneID="eSO-yw-CxQ">
            <objects>
                <viewController id="g8o-Tr-qN9" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="maR-va-yyC"/>
                        <viewControllerLayoutGuide type="bottom" id="tDB-f3-oGv"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="jgk-vn-mfX">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                    </view>
                    <navigationItem key="navigationItem" id="fla-GE-9dz"/>
                    <simulatedScreenMetrics key="simulatedDestinationMetrics"/>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="vae-Ar-iZP" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="67" y="369"/>
        </scene>
    </scenes>
</document>


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/DelegateProtocols/PostSectionControllerDelegate.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

/// To allow communication between PostSectionController and FeedViewController
protocol PostSectionControllerDelegate: AnyObject {
    func postSectionController(_ sectionController: PostSectionController, didSelectOptionsFor post: Post, from sourceView: UIView)
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Extensions/UIActivityIndicatorView+Extension.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

extension UIActivityIndicatorView {

    class var defaultStyle: UIActivityIndicatorView.Style {
        if #available(iOS 13.0, *) {
            return .medium
        } else {
            return .gray
        }
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Extensions/UIColor+Extension.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

extension UIColor {

    class var background: UIColor {
        if #available(iOS 13.0, *) {
            return .systemBackground
        } else {
            return .white
        }
    }

    class var groupedBackground: UIColor {
        if #available(iOS 13.0, *) {
            return .systemGroupedBackground
        } else {
            return .groupTableViewBackground
        }
    }

    class var secondaryGroupedBackground: UIColor {
        if #available(iOS 13.0, *) {
            return .secondarySystemGroupedBackground
        } else {
            return .white
        }
    }

    class var secondaryBackground: UIColor {
        if #available(iOS 13.0, *) {
            return .secondarySystemBackground
        } else {
            return .lightGray
        }
    }

    class var defaultSeparator: UIColor {
        if #available(iOS 13.0, *) {
            return UIColor.separator
        } else {
            return UIColor(red: 200 / 255.0,
                           green: 199 / 255.0,
                           blue: 204 / 255.0,
                           alpha: 1)
        }
    }

    class var titleLabel: UIColor {
        if #available(iOS 13.0, *) {
            return .label
        } else {
            return .darkText
        }
    }

    class var detailLabel: UIColor {
        if #available(iOS 13.0, *) {
            return .secondaryLabel
        } else {
            return .lightGray
        }
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/IGListKitExamples.entitlements
================================================
<?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>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.network.client</key>
	<true/>
</dict>
</plist>


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/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>$(DEVELOPMENT_LANGUAGE)</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>IGListKit</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>LSRequiresIPhoneOS</key>
	<false/>
	<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSAllowsArbitraryLoads</key>
		<true/>
	</dict>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
	</array>
</dict>
</plist>


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/APIService.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation

// MARK: - Data Provider

// In IGListKit architecture, the data provider is separated from the UI components
// This enables clean separation of concerns and makes testing easier
class APIService {
    static let shared = APIService()

    // Pagination state
    private var currentPage = 1
    private var isLoading = false
    private var hasMoreData = true

    // Fetch posts with pagination support
    // This is called by the view controller to load data
    // IGListKit will handle the diffing and UI updates based on the results
    func fetchPosts(completion: @escaping ([Post]) -> Void) {
        guard !isLoading, hasMoreData else { return }

        self.isLoading = true

        // Simulate network delay
        DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) {
            let posts = self.generateMockPosts(page: self.currentPage)

            if self.currentPage >= 5 {
                self.hasMoreData = false
            }

            self.currentPage += 1
            self.isLoading = false

            DispatchQueue.main.async {
                completion(posts)
            }
        }
    }

    // Reset pagination state for refreshing
    func resetPagination() {
        self.currentPage = 1
        self.hasMoreData = true
    }

    // Generate mock data for the demo app
    // In a real app, this would be replaced with API calls
    func generateMockPosts(page: Int) -> [Post] {
        let baseCount = (page - 1) * 5

        return (1...5).map { index in
            let id = "\(baseCount + index)"
            return Post(
                id: id,
                username: "user\(Int.random(in: 100...999))",
                userAvatarURL: URL(string: "https://randomuser.me/api/portraits/men/\(Int.random(in: 1...99)).jpg"),
                imageURL: URL(string: "https://picsum.photos/id/\(baseCount + index + 10)/500/500"),
                title: "Post #\(id)",
                description: "This is a beautiful photo I took while traveling. What do you think? #travel #photography #nature",
                likes: Int.random(in: 10...1000),
                timeStamp: Date().addingTimeInterval(-Double(Int.random(in: 1...86400) * (baseCount + index)))
            )
        }
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/ActivityItem.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit

final class ActivityItem: ListDiffable {

    let bodyText: String
    let header: String?
    let footer: String?

    init(bodyText: String, header: String? = nil, footer: String? = nil) {
        self.bodyText = bodyText
        self.header = header
        self.footer = footer
    }

    // MARK: ListDiffable

    func diffIdentifier() -> NSObjectProtocol {
        return bodyText as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        guard self !== object else { return true }
        guard let object = object as? ActivityItem else { return false }
        return bodyText == object.bodyText
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/FeedItem.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit

final class FeedItem: ListDiffable {

    let pk: Int
    let user: User
    let comments: [String]

    init(pk: Int, user: User, comments: [String]) {
        self.pk = pk
        self.user = user
        self.comments = comments
    }

    // MARK: ListDiffable

    func diffIdentifier() -> NSObjectProtocol {
        return pk as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        guard self !== object else { return true }
        guard let object = object as? FeedItem else { return false }
        return user.isEqual(toDiffableObject: object.user) && comments == object.comments
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/GridItem.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import Foundation

final class GridItem: NSObject {

    let color: UIColor
    let itemCount: Int

    var items: [String] = []

    init(color: UIColor, itemCount: Int) {
        self.color = color
        self.itemCount = itemCount

        super.init()

        self.items = computeItems()
    }

    private func computeItems() -> [String] {
        return [Int](1...itemCount).map {
            String(describing: $0)
        }
    }
}

extension GridItem: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return self
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        return self === object ? true : self.isEqual(object)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/HorizontalCardsSection.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import Foundation

final class HorizontalCardsSection: NSObject {

    let cardCount: Int
    private(set) var items: [String] = []

    init(cardCount: Int) {
        self.cardCount = cardCount
        super.init()
        self.items = computeItems()
    }

    private func computeItems() -> [String] {
        return [Int](1...cardCount).map {
            String(describing: $0)
        }
    }
}

extension HorizontalCardsSection: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return self
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        return self === object ? true : self.isEqual(object)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/LoadingCellModel.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit
import IGListKit

final class LoadingCellModel {
    let identifier = "loading-cell"
}

// MARK: - ListDiffable Implementation

// Even simple models like this loading indicator need to conform to ListDiffable
// in order to be used with IGListKit
extension LoadingCellModel: ListDiffable {

    // The diffIdentifier uniquely identifies this object
    // For a singleton loading indicator, a static string ID is sufficient
    func diffIdentifier() -> any NSObjectProtocol {
        return self.identifier as NSObjectProtocol
    }

    // isEqual compares properties that affect the visual representation
    // For this simple case, comparing identifiers is enough
    func isEqual(toDiffableObject object: (any ListDiffable)?) -> Bool {
        guard let object = object as? LoadingCellModel else { return false }
        return self.identifier == object.identifier
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/Month.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import IGListKit

final class Month {

    let name: String
    let days: Int

    // day int mapped to an array of appointment names
    let appointments: [Int: [NSString]]

    init(name: String, days: Int, appointments: [Int: [NSString]]) {
        self.name = name
        self.days = days
        self.appointments = appointments
    }

}

extension Month: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return name as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        return true
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/Post.h
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import <Foundation/Foundation.h>

@import IGListDiffKit;

@interface Post : NSObject <IGListDiffable>

@property (nonatomic, strong, readonly) NSString *username;
@property (nonatomic, strong, readonly) NSArray<NSString *> *comments;

- (instancetype)initWithUsername:(NSString *)username
                        comments:(NSArray<NSString *> *)comments NS_DESIGNATED_INITIALIZER;

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

@end


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/Post.m
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import "Post.h"

@implementation Post

- (instancetype)initWithUsername:(NSString *)username
                        comments:(NSArray<NSString *> *)comments {
    if (self = [super init]) {
        _username = [username copy];
        _comments = [comments copy];
    }
    return self;
}

#pragma mark - IGListDiffable

- (id<NSObject>)diffIdentifier {
    return self;
}

- (BOOL)isEqualToDiffableObject:(id)object {
    // since the diff identifier returns self, object should only be compared with same instance
    return self == object;
}

@end


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/PostModel.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class Post {
    let id: String
    let username: String
    let userAvatarURL: URL?
    let imageURL: URL?
    let title: String
    let description: String
    let likes: Int
    let timeStamp: Date

    init(id: String, username: String, userAvatarURL: URL?, imageURL: URL?, title: String, description: String, likes: Int, timeStamp: Date) {
        self.id = id
        self.username = username
        self.userAvatarURL = userAvatarURL
        self.imageURL = imageURL
        self.title = title
        self.description = description
        self.likes = likes
        self.timeStamp = timeStamp
    }
}

// MARK: - ListDiffable Implementation

// ListDiffable is the core protocol in IGListKit for data diffing
// It's similar to Equatable but with more specific requirements for efficient diffing
extension Post: ListDiffable {

    // This method returns a unique identifier for the object
    // IGListKit uses this to track objects across updates
    // It should be unique and stable across updates (like a database ID)
    func diffIdentifier() -> NSObjectProtocol {
        return self.id as NSObjectProtocol
    }

    // This method compares all properties that might cause visual changes
    // If this returns false for objects with the same diffIdentifier,
    // IGListKit will reload that section instead of leaving it alone
    func isEqual(toDiffableObject object: (any ListDiffable)?) -> Bool {
        guard let object = object as? Post else { return false }

        return self.id == object.id &&
               self.username == object.username &&
               self.userAvatarURL == object.userAvatarURL &&
               self.imageURL == object.imageURL &&
               self.title == object.title &&
               self.description == object.description &&
               self.likes == object.likes
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.h
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

/**
 * This file is generated using the remodel generation script.
 * The name of the input file is PersonModel.value
 */

#import <Foundation/Foundation.h>

@import IGListDiffKit;

@interface PersonModel : NSObject <IGListDiffable, NSCopying>

@property (nonatomic, readonly, copy) NSString *firstName;
@property (nonatomic, readonly, copy) NSString *lastName;
@property (nonatomic, readonly, copy) NSString *uniqueId;

+ (instancetype)new NS_UNAVAILABLE;

- (instancetype)init NS_UNAVAILABLE;

- (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName uniqueId:(NSString *)uniqueId NS_DESIGNATED_INITIALIZER;

@end


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.m
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

/**
 * This file is generated using the remodel generation script.
 * The name of the input file is PersonModel.value
 */

#if  ! __has_feature(objc_arc)
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif

#import "PersonModel.h"

@implementation PersonModel

- (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName uniqueId:(NSString *)uniqueId
{
  if ((self = [super init])) {
    _firstName = [firstName copy];
    _lastName = [lastName copy];
    _uniqueId = [uniqueId copy];
  }

  return self;
}

- (id)copyWithZone:(nullable NSZone *)zone
{
  return self;
}

- (NSString *)description
{
  return [NSString stringWithFormat:@"%@ - \n\t firstName: %@; \n\t lastName: %@; \n\t uniqueId: %@; \n", [super description], _firstName, _lastName, _uniqueId];
}

- (id<NSObject>)diffIdentifier
{
  return _uniqueId;
}

- (NSUInteger)hash
{
  NSUInteger subhashes[] = {[_firstName hash], [_lastName hash], [_uniqueId hash]};
  NSUInteger result = subhashes[0];
  for (int ii = 1; ii < 3; ++ii) {
    unsigned long long base = (((unsigned long long)result) << 32 | subhashes[ii]);
    base = (~base) + (base << 18);
    base ^= (base >> 31);
    base *=  21;
    base ^= (base >> 11);
    base += (base << 6);
    base ^= (base >> 22);
    result = base;
  }
  return result;
}

- (BOOL)isEqual:(PersonModel *)object
{
  if (self == object) {
    return YES;
  } else if (self == nil || object == nil || ![object isKindOfClass:[self class]]) {
    return NO;
  }
  return
    (_firstName == object->_firstName ? YES : [_firstName isEqual:object->_firstName]) &&
    (_lastName == object->_lastName ? YES : [_lastName isEqual:object->_lastName]) &&
    (_uniqueId == object->_uniqueId ? YES : [_uniqueId isEqual:object->_uniqueId]);
}

- (BOOL)isEqualToDiffableObject:(nullable id<IGListDiffable>)object
{
  return [self isEqual:object];
}

@end


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.value
================================================
PersonModel includes(IGListDiffable) {
  NSString *firstName
  NSString *lastName
  %diffIdentifier
  NSString *uniqueId
}

================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/SelectionModel.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit

enum SelectionModelType: Int {
    case none, fullWidth, nib
}

final class SelectionModel: NSObject {

    let options: [String]
    let type: SelectionModelType

    init(options: [String], type: SelectionModelType = .none) {
        self.options = options
        self.type = type
    }

}

extension SelectionModel: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return self
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        return isEqual(object)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/SwipeActionSection.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import Foundation

final class SwipeActionSection: NSObject {

}

extension SwipeActionSection: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return self
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        return self === object ? true : self.isEqual(object)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/User.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit

final class User: ListDiffable {

    let pk: Int
    let name: String
    let handle: String

    init(pk: Int, name: String, handle: String) {
        self.pk = pk
        self.name = name
        self.handle = handle
    }

    // MARK: ListDiffable

    func diffIdentifier() -> NSObjectProtocol {
        return pk as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        guard self !== object else { return true }
        guard let object = object as? User else { return false }
        return name == object.name && handle == object.handle
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/ViewModels/DayViewModel.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import IGListKit

final class DayViewModel {

    let day: Int
    let today: Bool
    let selected: Bool
    let appointments: Int

    init(day: Int, today: Bool, selected: Bool, appointments: Int) {
        self.day = day
        self.today = today
        self.selected = selected
        self.appointments = appointments
    }

}

extension DayViewModel: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return day as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        if self === object { return true }
        guard let object = object as? DayViewModel else { return false }
        return today == object.today && selected == object.selected && appointments == object.appointments
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Models/ViewModels/MonthTitleViewModel.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Foundation
import IGListKit

final class MonthTitleViewModel {

    let name: String

    init(name: String) {
        self.name = name
    }

}

extension MonthTitleViewModel: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return name as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        if self === object { return true }
        guard object is MonthTitleViewModel else { return false }
        // name is checked in the diffidentifier, so we can assume its equal
        return true
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/DemoSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class DemoItem: NSObject {

    let name: String
    let imageName: String
    let controllerClass: UIViewController.Type
    let controllerIdentifier: String?

    init(
        name: String,
        imageName: String,
        controllerClass: UIViewController.Type,
        controllerIdentifier: String? = nil
        ) {
        self.name = name
        self.imageName = imageName
        self.controllerClass = controllerClass
        self.controllerIdentifier = controllerIdentifier
    }

}

extension DemoItem: ListDiffable {

    func diffIdentifier() -> NSObjectProtocol {
        return name as NSObjectProtocol
    }

    func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
        if self === object { return true }
        guard let object = object as? DemoItem else { return false }
        return controllerClass == object.controllerClass && controllerIdentifier == object.controllerIdentifier
    }

}

final class DemoSectionController: ListSectionController {
    private var object: DemoItem?

    override func sizeForItem(at index: Int) -> CGSize {
        guard let context = collectionContext else {
            return .zero
        }
        let inset = context.containerInset
        let safeArea = viewController?.view.safeAreaInsets ?? .zero
        let width = context.containerSize.width - (inset.left + inset.right + safeArea.left + safeArea.right)
        return CGSize(width: width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = object?.name
        cell.imageName = object?.imageName
        cell.style = .grouped
        cell.isTopCell = isFirstSection
        cell.isBottomCell = isLastSection
        if let splitViewController = viewController?.splitViewController {
            cell.disclosureImageView.isHidden = splitViewController.viewControllers.count > 1
        }
        cell.separator.isHidden = cell.isSelected
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = object as? DemoItem
    }

    override func didSelectItem(at index: Int) {
        setSeparatorsHidden(true)

        let navigationController = UINavigationController()
        navigationController.navigationBar.prefersLargeTitles = true

        if let identifier = object?.controllerIdentifier {
            let storyboard = UIStoryboard(name: "Demo", bundle: nil)
            let controller = storyboard.instantiateViewController(withIdentifier: identifier)
            controller.title = object?.name
            navigationController.viewControllers = [controller]
            viewController?.showDetailViewController(navigationController, sender: self)
        } else if let controller = object?.controllerClass.init() {
            controller.title = object?.name
            navigationController.viewControllers = [controller]
            viewController?.showDetailViewController(navigationController, sender: self)
        }
    }

    override func didDeselectItem(at index: Int) {
        setSeparatorsHidden(false)
    }

    private func setSeparatorsHidden(_ hidden: Bool) {
        if let cell = collectionContext.cellForItem(at: 0, sectionController: self) as? LabelCell {
            cell.separator.isHidden = hidden
        }

        if section > 0,
           let listAdapter = collectionContext as? ListAdapter,
           let previousSectionController = listAdapter.sectionController(forSection: section - 1),
           let previousCell = collectionContext.cellForItem(at: 0, sectionController: previousSectionController) as? LabelCell {
            previousCell.separator.isHidden = hidden
        }
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/DisplaySectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit
import UIKit

final class DisplaySectionController: ListSectionController, ListDisplayDelegate {

    override init() {
        super.init()
        displayDelegate = self
        inset = UIEdgeInsets(top: 0, left: 0, bottom: 30, right: 0)
    }

    override func numberOfItems() -> Int {
        return 4
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = "Section \(self.section), cell \(index)"
        return cell
    }

    // MARK: ListDisplayDelegate

    func listAdapter(_ listAdapter: ListAdapter, willDisplay sectionController: ListSectionController) {
        print("Will display section \(self.section)")
    }

    func listAdapter(_ listAdapter: ListAdapter,
                     willDisplay sectionController: ListSectionController,
                     cell: UICollectionViewCell,
                     at index: Int) {
                       print("Did will display cell \(index) in section \(self.section)")
    }

    func listAdapter(_ listAdapter: ListAdapter, didEndDisplaying sectionController: ListSectionController) {
        print("Did end displaying section \(self.section)")
    }

    func listAdapter(_ listAdapter: ListAdapter,
                     didEndDisplaying sectionController: ListSectionController,
                     cell: UICollectionViewCell,
                     at index: Int) {
                       print("Did end displaying cell \(index) in section \(self.section)")
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/EmbeddedSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit
import UIKit

final class EmbeddedSectionController: ListSectionController {

    private var number: Int?

    override init() {
        super.init()
        self.inset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)
    }

    override func sizeForItem(at index: Int) -> CGSize {
        let height = collectionContext?.containerSize.height ?? 0
        return CGSize(width: height, height: height)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: CenterLabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        let value = number ?? 0
        cell.text = "\(value + 1)"
        cell.backgroundColor = UIColor(red: 237 / 255.0, green: 73 / 255.0, blue: 86 / 255.0, alpha: 1)
        return cell
    }

    override func didUpdate(to object: Any) {
        number = object as? Int
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/ExpandableSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit
import UIKit

final class ExpandableSectionController: ListSectionController {

    private var expanded = false
    private var object: String?

    override func sizeForItem(at index: Int) -> CGSize {
        let width = collectionContext!.containerSize.width
        let height = expanded ? LabelCell.textHeight(object ?? "", width: width) : LabelCell.singleLineHeight
        return CGSize(width: width, height: height)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = object
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = object as? String
    }

    override func didSelectItem(at index: Int) {
        expanded = !expanded
        UIView.animate(withDuration: 0.5,
                       delay: 0,
                       usingSpringWithDamping: 0.4,
                       initialSpringVelocity: 0.6,
                       options: [],
                       animations: {
                        self.collectionContext?.invalidateLayout(for: self)
        })
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/FeedItemSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit

final class FeedItemSectionController: ListSectionController, ListSupplementaryViewSource {

    private var feedItem: FeedItem!

    override init() {
        super.init()
        supplementaryViewSource = self
    }

    // MARK: IGListSectionController Overrides

    override func numberOfItems() -> Int {
        return feedItem.comments.count
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = feedItem.comments[index]
        return cell
    }

    override func didUpdate(to object: Any) {
        feedItem = object as? FeedItem
    }

    // MARK: ListSupplementaryViewSource

    func supportedElementKinds() -> [String] {
        return [UICollectionView.elementKindSectionHeader, UICollectionView.elementKindSectionFooter]
    }

    func viewForSupplementaryElement(ofKind elementKind: String, at index: Int) -> UICollectionReusableView {
        switch elementKind {
        case UICollectionView.elementKindSectionHeader:
            return userHeaderView(atIndex: index)
        case UICollectionView.elementKindSectionFooter:
            return userFooterView(atIndex: index)
        default:
            fatalError()
        }
    }

    func sizeForSupplementaryView(ofKind elementKind: String, at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 40)
    }

    // MARK: Private
    private func userHeaderView(atIndex index: Int) -> UICollectionReusableView {
        let view: UserHeaderView = collectionContext.dequeueReusableSupplementaryView(
            ofKind: UICollectionView.elementKindSectionHeader,
            forSectionController: self,
            nibName: "UserHeaderView",
            bundle: nil,
            atIndex: index)
        view.handle = "@" + feedItem.user.handle
        view.name = feedItem.user.name
        return view
    }

    private func userFooterView(atIndex index: Int) -> UICollectionReusableView {
        let view: UserFooterView = collectionContext.dequeueReusableSupplementaryView(
            ofKind: UICollectionView.elementKindSectionFooter,
            forSectionController: self,
            nibName: "UserFooterView",
            bundle: nil,
            atIndex: index)
        view.commentsCount = "\(feedItem.comments.count)"
        return view
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/GridSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit
import UIKit

final class GridSectionController: ListSectionController {

    private var object: GridItem?
    private let isReorderable: Bool

    required init(isReorderable: Bool = false) {
        self.isReorderable = isReorderable
        super.init()
        self.minimumInteritemSpacing = 1
        self.minimumLineSpacing = 1
    }

    override func numberOfItems() -> Int {
        return object?.itemCount ?? 0
    }

    override func sizeForItem(at index: Int) -> CGSize {
        let itemsPerRow = 4.0
        let width = (collectionContext?.containerSize.width ?? 0) - ((itemsPerRow - 1) * self.minimumLineSpacing)
        let itemSize = floor(width / itemsPerRow)
        return CGSize(width: itemSize, height: itemSize)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: CenterLabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = object?.items[index] ?? "undefined"
        cell.backgroundColor = object?.color
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = object as? GridItem
    }

    override func canMoveItem(at index: Int) -> Bool {
        return isReorderable
    }

    override func moveObject(from sourceIndex: Int, to destinationIndex: Int) {
        guard let object = object else { return }
        let item = object.items.remove(at: sourceIndex)
        object.items.insert(item, at: destinationIndex)
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/HorizontalSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class HorizontalSectionController: ListSectionController, ListAdapterDataSource {

    private var number: Int?

    lazy var adapter: ListAdapter = {
        let adapter = ListAdapter(updater: ListAdapterUpdater(),
                                  viewController: self.viewController)
        adapter.dataSource = self
        return adapter
    }()

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 100)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: EmbeddedCollectionViewCell = collectionContext.dequeueReusableCell(for: self, at: index)
        adapter.collectionView = cell.collectionView
        return cell
    }

    override func didUpdate(to object: Any) {
        number = object as? Int
    }

    // MARK: ListAdapterDataSource

    func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
        guard let number = number else { return [] }
        return (0..<number).map { $0 as ListDiffable }
    }

    func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
        return EmbeddedSectionController()
    }

    func emptyView(for listAdapter: ListAdapter) -> UIView? {
        return nil
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/LabelSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit
import UIKit

final class LabelSectionController: ListSectionController {

    private var object: String?

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = object
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = String(describing: object)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/ListeningSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit

final class ListeningSectionController: ListSectionController, IncrementListener {

    private var value: Int = 0

    init(announcer: IncrementAnnouncer) {
        super.init()
        announcer.addListener(listener: self)
    }

    func configureCell(cell: LabelCell) {
        cell.text = "Section: \(self.section), value: \(value)"
    }

    // MARK: ListSectionController Overrides

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        configureCell(cell: cell)
        return cell
    }

    // MARK: IncrementListener

    func didIncrement(announcer: IncrementAnnouncer, value: Int) {
        self.value = value
        guard let cell = collectionContext?.cellForItem(at: 0, sectionController: self) as? LabelCell else { return }
        configureCell(cell: cell)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/LoadingSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit

// MARK: - LoadingSectionController

// A simpler section controller that manages the loading indicator
// Note that each type of content gets its own section controller
// This is a key concept in IGListKit - each model type gets a dedicated controller
final class LoadingSectionController: ListSectionController {

    override init() {
        super.init()
        self.inset = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 0)
    }

    // Set the size for the loading indicator cell
    override func sizeForItem(at index: Int) -> CGSize {
        let width = collectionContext?.containerSize.width ?? 0
        return CGSize(width: width, height: 60)
    }

    // Create and return the loading cell
    override func cellForItem(at index: Int) -> UICollectionViewCell {
        guard let cell = collectionContext?.dequeueReusableCell(of: LoadingCell.self, for: self, at: index) else {
            fatalError("Failed to dequeue LoadingCell")
        }
        return cell
    }

    // Nothing to update for this simple controller
    override func didUpdate(to object: Any) {
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/MonthSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class MonthSectionController: ListBindingSectionController<ListDiffable>, ListBindingSectionControllerDataSource, ListBindingSectionControllerSelectionDelegate {

    private var selectedDay: Int = -1

    override init() {
        super.init()
        dataSource = self
        selectionDelegate = self
    }

    // MARK: ListBindingSectionControllerDataSource

    func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, viewModelsFor object: Any) -> [ListDiffable] {
        guard let month = object as? Month else { return [] }

        let date = Date()
        let today = Calendar.current.component(.day, from: date)

        var viewModels = [ListDiffable]()

        viewModels.append(MonthTitleViewModel(name: month.name))

        for day in 1..<(month.days + 1) {
            let viewModel = DayViewModel(
                day: day,
                today: day == today,
                selected: day == selectedDay,
                appointments: month.appointments[day]?.count ?? 0
            )
            viewModels.append(viewModel)
        }

        for appointment in month.appointments[selectedDay] ?? [] {
            viewModels.append(appointment)
        }

        return viewModels
    }

    func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>,
                           cellForViewModel viewModel: Any,
                           at index: Int) -> UICollectionViewCell & ListBindable {
        switch viewModel {
        case is DayViewModel:
            return collectionContext.dequeueReusableCell(for: self, at: index) as CalendarDayCell
        case is MonthTitleViewModel:
            return collectionContext.dequeueReusableCell(for: self, at: index) as MonthTitleCell
        default:
            return collectionContext.dequeueReusableCell(for: self, at: index) as LabelCell
        }
    }

    func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>,
                           sizeForViewModel viewModel: Any,
                           at index: Int) -> CGSize {
        guard let width = collectionContext?.containerSize.width else { return .zero }
        if viewModel is DayViewModel {
            let square = width / 7.0
            return CGSize(width: square, height: square)
        } else if viewModel is MonthTitleViewModel {
            return CGSize(width: width, height: 30.0)
        } else {
            return CGSize(width: width, height: 55.0)
        }
    }

    // MARK: ListBindingSectionControllerSelectionDelegate

    func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, didSelectItemAt index: Int, viewModel: Any) {
        guard let dayViewModel = viewModel as? DayViewModel else { return }
        if dayViewModel.day == selectedDay {
            selectedDay = -1
        } else {
            selectedDay = dayViewModel.day
        }
        update(animated: true)
    }

    func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, didDeselectItemAt index: Int, viewModel: Any) {}

    func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, didHighlightItemAt index: Int, viewModel: Any) {}

    func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, didUnhighlightItemAt index: Int, viewModel: Any) {}

    @available(iOS 13.0, *)
    func sectionController(_ sectionController: ListBindingSectionController<ListDiffable>, contextMenuConfigurationForItemAt index: Int, point: CGPoint, viewModel: Any) -> UIContextMenuConfiguration? {
        return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
            // Create an action for sharing
            let share = UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up")) { _ in
                // Show share sheet
            }

            // Create an action for copy
            let rename = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc")) { _ in
                // Perform copy
            }

            // Create an action for delete with destructive attributes (highligh in red)
            let delete = UIAction(title: "Delete", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in
                // Perform delete
            }

            // Create a UIMenu with all the actions as children
            return UIMenu(title: "", children: [share, rename, delete])
        }
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PersonSectionController.h
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

@import IGListKit;

@interface PersonSectionController : IGListSectionController

@end


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PersonSectionController.m
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import "PersonSectionController.h"

#import "PersonCell.h"
#import "PersonModel.h"

@implementation PersonSectionController {
    PersonModel *_person;
}

#pragma mark - IGListSectionController Overrides

- (NSInteger)numberOfItems {
    return 1;
}

- (CGSize)sizeForItemAtIndex:(NSInteger)index {
    const CGFloat width = self.collectionContext.containerSize.width;
    const CGFloat height = 74.0;
    return CGSizeMake(width, height);
}

- (UICollectionViewCell *)cellForItemAtIndex:(NSInteger)index {
    const Class cellClass = [PersonCell class];
    PersonCell *cell = (PersonCell *)[self.collectionContext dequeueReusableCellOfClass:cellClass forSectionController:self atIndex:index];
    cell.person = _person;
    return cell;
}

- (void)didUpdateToObject:(id)object {
    _person = (PersonModel *)object;
}

@end


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.h
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

@import IGListKit;

@interface PostSectionController : IGListSectionController

@end


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.m
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import "PostSectionController.h"

#import "CommentCell.h"
#import "InteractiveCell.h"
#import "PhotoCell.h"
#import "Post.h"
#import "UserInfoCell.h"

static NSInteger cellsBeforeComments = 3;

@implementation PostSectionController {
    Post *_post;
}

#pragma mark - IGListSectionController Overrides

- (NSInteger)numberOfItems {
    return cellsBeforeComments + _post.comments.count;
}

- (CGSize)sizeForItemAtIndex:(NSInteger)index {
    const CGFloat width = self.collectionContext.containerSize.width;
    CGFloat height;
    if (index == 0 || index == 2) {
        height = 41.0;
    } else if (index == 1) {
        height = width; // square
    } else {
        height = 25.0;
    }
    return CGSizeMake(width, height);
}

- (UICollectionViewCell *)cellForItemAtIndex:(NSInteger)index {
    Class cellClass;
    if (index == 0) {
        cellClass = [UserInfoCell class];
    } else if (index == 1) {
        cellClass = [PhotoCell class];
    } else if (index == 2) {
        cellClass = [InteractiveCell class];
    } else {
        cellClass = [CommentCell class];
    }
    id cell = [self.collectionContext dequeueReusableCellOfClass:cellClass forSectionController:self atIndex:index];
    if ([cell isKindOfClass:[CommentCell class]]) {
        [(CommentCell *)cell setComment:_post.comments[index - cellsBeforeComments]];
    } else if ([cell isKindOfClass:[UserInfoCell class]]) {
        [(UserInfoCell *)cell setName:_post.username];
    }
    return cell;
}

- (void)didUpdateToObject:(id)object {
    _post = object;
}

@end


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit

// MARK: - ListSectionController

// In IGListKit, section controllers manage a single type of data object
// and are responsible for:
// - Creating and configuring cells
// - Handling cell selection
// - Determining cell sizes
// - Managing section-specific actions
final class PostSectionController: ListSectionController {

    var post: Post?
    weak var delegate: PostSectionControllerDelegate?

    override init() {
        super.init()
        // Setting insets for the entire section
        self.inset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
    }

    // Determines the size of cells in this section
    // IGListKit calls this method to calculate cell dimensions
    override func sizeForItem(at index: Int) -> CGSize {
        // collectionContext is a bridge that connects the section controller
        // to the actual UICollectionView it exists within
        let width = collectionContext?.containerSize.width ?? 0
        return CGSize(width: width, height: width + 200)
    }

    // Creates and configures a cell for this section
    // Similar to cellForRowAt in UICollectionViewDataSource
    override func cellForItem(at index: Int) -> UICollectionViewCell {
        guard let cell = collectionContext?.dequeueReusableCell(of: PostCell.self, for: self, at: index) as? PostCell,
              let post = post else {
            fatalError("Failed to dequeue PostCell")
        }

        cell.configure(with: post)

        cell.optionsButtonTapped = { [weak self] (button: UIButton) in
            guard let self = self, let post = self.post else { return }
            self.delegate?.postSectionController(self, didSelectOptionsFor: post, from: button)
        }

        return cell
    }

    // Handles selection of cells in this section
    override func didSelectItem(at index: Int) {
        guard let post = post else { return }
        print("Post ID:\(post.id) was tapped.")
    }

    // Called when the data object for this section controller is updated
    // This is where you store a reference to your model object
    override func didUpdate(to object: Any) {
        post = object as? Post
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/RemoveSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit

protocol RemoveSectionControllerDelegate: AnyObject {
    func removeSectionControllerWantsRemoved(_ sectionController: RemoveSectionController)
}

final class RemoveSectionController: ListSectionController, RemoveCellDelegate {

    weak var delegate: RemoveSectionControllerDelegate?
    private var number: Int?

    override init() {
        super.init()
        inset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: RemoveCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = "Cell: \((number ?? 0) + 1)"
        cell.delegate = self
        return cell
    }

    override func didUpdate(to object: Any) {
        number = object as? Int
    }

    // MARK: RemoveCellDelegate

    func removeCellDidTapButton(_ cell: RemoveCell) {
        delegate?.removeSectionControllerWantsRemoved(self)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/ReorderableSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit
import UIKit

final class ReorderableSectionController: ListSectionController {

    private var object: String?

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: LabelCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = object
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = String(describing: object)
    }

    override func canMoveItem(at index: Int) -> Bool {
        return true
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/SearchSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit

protocol SearchSectionControllerDelegate: AnyObject {
    func searchSectionController(_ sectionController: SearchSectionController, didChangeText text: String)
}

final class SearchSectionController: ListSectionController, UISearchBarDelegate, ListScrollDelegate {

    weak var delegate: SearchSectionControllerDelegate?

    override init() {
        super.init()
        scrollDelegate = self
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 44)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: SearchCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.searchBar.delegate = self
        return cell
    }

    // MARK: UISearchBarDelegate

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        delegate?.searchSectionController(self, didChangeText: searchText)
    }

    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        delegate?.searchSectionController(self, didChangeText: searchBar.text!)
    }

    // MARK: ListScrollDelegate

    func listAdapter(_ listAdapter: ListAdapter, didScroll sectionController: ListSectionController) {
        if let searchBar = (collectionContext?.cellForItem(at: 0, sectionController: self) as? SearchCell)?.searchBar {
            searchBar.resignFirstResponder()
        }
    }

    func listAdapter(_ listAdapter: ListAdapter, willBeginDragging sectionController: ListSectionController) {}
    func listAdapter(_ listAdapter: ListAdapter,
                     didEndDragging sectionController: ListSectionController,
                     willDecelerate decelerate: Bool) {}

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/SelfSizingSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import IGListSwiftKit
import UIKit

final class SelfSizingSectionController: ListSectionController {

    private var model: SelectionModel!

    override init() {
        super.init()
        inset = UIEdgeInsets(top: 0, left: 0, bottom: 40, right: 0)
        minimumLineSpacing = 4
        minimumInteritemSpacing = 4
    }

    override func numberOfItems() -> Int {
        return model.options.count
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let text = model.options[index]
        let cell: UICollectionViewCell
        switch model.type {
        case .none:
            let manualCell: ManuallySelfSizingCell = collectionContext.dequeueReusableCell(
                for: self,
                at: index
            )
            manualCell.text = text
            cell = manualCell
        case .fullWidth:
            let manualCell: FullWidthSelfSizingCell = collectionContext.dequeueReusableCell(
                for: self,
                at: index
            )
            manualCell.text = text
            cell = manualCell
        case .nib:
            let nibCell: NibSelfSizingCell = collectionContext.dequeueReusableCell(
                withNibName: "NibSelfSizingCell",
                bundle: nil,
                for: self,
                at: index
            )
            nibCell.contentLabel.text = text
            cell = nibCell
        }
        return cell
    }

    override func didUpdate(to object: Any) {
        self.model = object as? SelectionModel
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/StoryboardLabelSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

protocol StoryboardLabelSectionControllerDelegate: AnyObject {
    func removeSectionControllerWantsRemoved(_ sectionController: StoryboardLabelSectionController)
}

final class StoryboardLabelSectionController: ListSectionController {

    private var object: Person?
    weak var delegate: StoryboardLabelSectionControllerDelegate?

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: (self.object?.name.count)! * 7, height: (self.object?.name.count)! * 7)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: StoryboardCell = collectionContext.dequeueReusableCellFromStoryboard(
            withIdentifier: "cell",
            for: self,
            at: index)
        cell.text = object?.name
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = object as? Person
    }

    override func didSelectItem(at index: Int) {
        delegate?.removeSectionControllerWantsRemoved(self)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/UserSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class UserSectionController: ListSectionController {

    private var user: User?
    private let isReorderable: Bool

    required init(isReorderable: Bool = false) {
        self.isReorderable = isReorderable
        super.init()
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: DetailLabelCell = collectionContext.dequeueReusableCell(
            for: self,
            at: index
        )
        cell.title = user?.name
        cell.detail = "@" + (user?.handle ?? "")
        return cell
    }

    override func didUpdate(to object: Any) {
        self.user = object as? User
    }

    override func canMoveItem(at index: Int) -> Bool {
        return isReorderable
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/ActivityComposableSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit
import SwiftUI

final class ActivityComposableSectionController: ListSectionController, CompositionLayoutCapable, ListSupplementaryViewSource {

    private var activity: ActivityItem?

    override init() {
        super.init()
        supplementaryViewSource = self
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: collectionContext!.containerSize.width, height: 60)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: UICollectionViewCell = collectionContext.dequeueReusableCell(
            for: self,
            at: index
        )
        cell.contentConfiguration = UIHostingConfiguration(content: {
            HStack {
                Circle()
                    .fill(
                        LinearGradient(colors: [ .blue.opacity(0.3), .red.opacity(0.3)],
                                       startPoint: .topLeading,
                                       endPoint: .bottomTrailing)
                    )
                    .frame(width: 44)
                    .padding(16)
                Text(activity?.bodyText ?? "No body")
                Spacer()
                RoundedRectangle(cornerRadius: 10)
                    .fill(
                        RadialGradient(colors: [ .green.opacity(0.3), .yellow.opacity(0.3)],
                                       center: .center,
                                       startRadius: 5,
                                       endRadius: 75)
                    )
                    .frame(width: 44, height: 44)
                    .padding(16)
            }
        })
        .margins(.all, 0)
        return cell
    }

    func supportedElementKinds() -> [String] {
        return [UICollectionView.elementKindSectionHeader, UICollectionView.elementKindSectionFooter]
    }

    func viewForSupplementaryElement(ofKind elementKind: String, at index: Int) -> UICollectionReusableView {
        let view: UICollectionViewListCell = collectionContext.dequeueReusableSupplementaryView(
            ofKind: elementKind,
            forSectionController: self,
            atIndex: index)
        view.contentConfiguration = UIHostingConfiguration(content: {
            switch elementKind {
            case UICollectionView.elementKindSectionHeader:
                Text("Activity Start")
            case UICollectionView.elementKindSectionFooter:
                Text("Activity End")
            default: EmptyView()
            }
        })
        return view
    }

    func sizeForSupplementaryView(ofKind elementKind: String, at index: Int) -> CGSize {
        if activity?.header != nil && elementKind == UICollectionView.elementKindSectionHeader {
            return CGSize(width: collectionContext.containerSize.width, height: 40)
        }
        if activity?.footer != nil && elementKind == UICollectionView.elementKindSectionFooter {
            return CGSize(width: collectionContext.containerSize.width, height: 40)
        }
        return .zero
    }

    override func didUpdate(to object: Any) {
        self.activity = object as? ActivityItem
    }

    // MARK: CompositionLayoutCapable

    func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
        var maxItemHeight: CGFloat = 0.0
        var anyItemHasEstimatedHeight = false
        let itemCount: Int = numberOfItems()
        let items = (0..<itemCount).map { itemIndex in
            let itemSize = sizeForItem(at: itemIndex)
            let layoutSize = NSCollectionLayoutSize(widthDimension: .absolute(itemSize.width),
                                                    heightDimension: .estimated(itemSize.height))
            maxItemHeight = max(maxItemHeight, itemSize.height)
            return NSCollectionLayoutItem(layoutSize: layoutSize)
        }

        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                               heightDimension: .estimated(maxItemHeight))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: items)
        if minimumInteritemSpacing > 0.0 {
            group.interItemSpacing = NSCollectionLayoutSpacing.fixed(minimumInteritemSpacing)
        }
        let layoutSection = NSCollectionLayoutSection(group: group)

        if let suplementaryViewProvider = supplementaryViewSource {
            layoutSection.boundarySupplementaryItems = suplementaryViewProvider.supportedElementKinds().map { kind in
                let size = suplementaryViewProvider.sizeForSupplementaryView(ofKind: kind, at: 0)
                let layoutSize = NSCollectionLayoutSize(widthDimension: .absolute(size.width), heightDimension: .absolute(size.height))
                let alignment: NSRectAlignment
                switch kind {
                case UICollectionView.elementKindSectionHeader: alignment = .top
                case UICollectionView.elementKindSectionFooter: alignment = .bottom
                default: alignment = .none
                }
                return NSCollectionLayoutBoundarySupplementaryItem(layoutSize: layoutSize, elementKind: kind, alignment: alignment)
            }
        }

        if inset != .zero {
            layoutSection.contentInsets = NSDirectionalEdgeInsets(top: inset.top,
                                                                  leading: inset.left,
                                                                  bottom: inset.bottom,
                                                                  trailing: inset.right)
        }
        if minimumLineSpacing > 0.0 {
            layoutSection.interGroupSpacing = minimumLineSpacing
        }
        return layoutSection
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/ExpandableComposableSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

/// Like ExpandableSectionController, but supports UICollectionViewCompositionalLayout
final class ExpandableComposableSectionController: ListSectionController, CompositionLayoutCapable {

    private var expanded = false
    private var object: String?

    override func sizeForItem(at index: Int) -> CGSize {
        // Size handled by cell
        return CGSize.zero
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: CompositionLayoutCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = object
        cell.expanded = expanded
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = object as? String
    }

    override func didSelectItem(at index: Int) {
        expanded = !expanded

        guard let cell = collectionContext.cellForItem(at: index, sectionController: self) as? CompositionLayoutCell else {
            return
        }
        cell.expanded = expanded

        UIView.animate(withDuration: 0.5,
                       delay: 0,
                       usingSpringWithDamping: 0.4,
                       initialSpringVelocity: 0.6,
                       options: [],
                       animations: {
                        self.collectionContext?.invalidateLayout(for: self)
        })
    }

    // MARK: CompositionLayoutCapable

    func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
        let config = UICollectionLayoutListConfiguration(appearance: .plain)
        return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/GridComposableSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class GridComposableSectionController: ListSectionController, CompositionLayoutCapable {

    private var object: GridItem?

    override func numberOfItems() -> Int {
        return object?.itemCount ?? 0
    }

    override func sizeForItem(at index: Int) -> CGSize {
        // Size handled by cell
        return CGSize.zero
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: CompositionLayoutCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = object?.items[index] ?? "undefined"
        cell.contentView.backgroundColor = object?.color
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = object as? GridItem
    }

    // MARK: CompositionLayoutCapable

    func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
        // Item
        let columnCount: CGFloat = 3
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0 / columnCount),
                                              heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)

        // Group
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                               heightDimension: .fractionalWidth(1.0 / columnCount))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
                                                       subitems: [item])

        // Section
        return NSCollectionLayoutSection(group: group)
    }
}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/HorizontalComposableSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class HorizontalComposableSectionController: ListSectionController, CompositionLayoutCapable {

    private var object: HorizontalCardsSection?

    override func numberOfItems() -> Int {
        return object?.cardCount ?? 0
    }

    override func sizeForItem(at index: Int) -> CGSize {
        // Size handled by cell
        return CGSize.zero
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: CompositionLayoutCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = object?.items[index] ?? "undefined"
        cell.contentView.backgroundColor = UIColor.secondarySystemBackground
        cell.contentView.layer.cornerRadius = 8
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = object as? HorizontalCardsSection
    }

    // MARK: CompositionLayoutCapable

    func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
        // Item
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                              heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 16)

        // Group
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(160))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

        // Section
        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = NSDirectionalEdgeInsets(top: 16, leading: 16, bottom: 16, trailing: 16)
        section.orthogonalScrollingBehavior = .continuousGroupLeadingBoundary
        return section
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/SelectionComposableSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit
import SwiftUI

final class TextViewModel: ObservableObject {
    @Published var text: String
    @Published var extraPadding: Bool = false

    init(text: String) {
        self.text = text
    }
}

struct ExpandTextView: View {
    @ObservedObject var viewModel: TextViewModel

    var body: some View {
        Text(viewModel.text)
            .padding(viewModel.extraPadding ? 20 : 10)
            .border(.gray.opacity(0.2), width: 1)
    }
}

final class SelectionComposableSectionController: ListSectionController, CompositionLayoutCapable {

    private var viewModels: [TextViewModel] = []

    override func numberOfItems() -> Int {
        return viewModels.count
    }

    override func sizeForItem(at index: Int) -> CGSize {
        return CGSize(width: 100, height: 55)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: UICollectionViewCell = collectionContext.dequeueReusableCell(
            for: self,
            at: index
        )
        let viewModel = viewModels[index]
        cell.contentConfiguration = UIHostingConfiguration(content: {
            ExpandTextView(viewModel: viewModel)
        })
        .margins(.all, 0)
        return cell
    }

    override func didSelectItem(at index: Int) {
        withAnimation {
            viewModels[index].extraPadding.toggle()
        }

    }

    override func didUpdate(to object: Any) {
        guard let selection = object as? SelectionModel else {
            return
        }
        viewModels = selection.options.map { TextViewModel(text: $0) }
    }

    // MARK: CompositionLayoutCapable

    func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
        var maxItemHeight: CGFloat = 0.0
        let itemCount: Int = numberOfItems()
        let items = (0..<itemCount).map { itemIndex in
            let itemSize = sizeForItem(at: itemIndex)
            let layoutSize = NSCollectionLayoutSize(widthDimension: .estimated(itemSize.width),
                                                    heightDimension: .estimated(itemSize.height))
            maxItemHeight = max(maxItemHeight, itemSize.height)
            return NSCollectionLayoutItem(layoutSize: layoutSize)
        }

        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                               heightDimension: .estimated(maxItemHeight))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: items)
        if minimumInteritemSpacing > 0.0 {
            group.interItemSpacing = NSCollectionLayoutSpacing.fixed(minimumInteritemSpacing)
        }
        let layoutSection = NSCollectionLayoutSection(group: group)

        if let suplementaryViewProvider = supplementaryViewSource {
            layoutSection.boundarySupplementaryItems = suplementaryViewProvider.supportedElementKinds().map { kind in
                let size = suplementaryViewProvider.sizeForSupplementaryView(ofKind: kind, at: 0)
                let layoutSize = NSCollectionLayoutSize(widthDimension: .absolute(size.width), heightDimension: .absolute(size.height))
                let alignment: NSRectAlignment
                switch kind {
                case UICollectionView.elementKindSectionHeader: alignment = .top
                case UICollectionView.elementKindSectionFooter: alignment = .bottom
                default: alignment = .none
                }
                return NSCollectionLayoutBoundarySupplementaryItem(layoutSize: layoutSize, elementKind: kind, alignment: alignment)
            }
        }

        if inset != .zero {
            layoutSection.contentInsets = NSDirectionalEdgeInsets(top: inset.top,
                                                                  leading: inset.left,
                                                                  bottom: inset.bottom,
                                                                  trailing: inset.right)
        }
        if minimumLineSpacing > 0.0 {
            layoutSection.interGroupSpacing = minimumLineSpacing
        }
        return layoutSection
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/SwipeActionComposabelSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class SwipeActionComposabelSectionController: ListSectionController, CompositionLayoutCapable {

    private var object: SwipeActionSection?

    private var items = ["1. Swipe to delete me", "2. Swipe to delete me", "3. Swipe to delete me"]

    override func numberOfItems() -> Int {
        return items.count
    }

    override func sizeForItem(at index: Int) -> CGSize {
        // Compositional layout doesn't request sizes per NSIndexPath
        return CGSize.zero
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: CompositionLayoutCell = collectionContext.dequeueReusableCell(for: self, at: index)
        cell.text = items[index]
        return cell
    }

    override func didUpdate(to object: Any) {
        self.object = object as? SwipeActionSection
    }

    func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
        var config = UICollectionLayoutListConfiguration(appearance: .plain)

        config.trailingSwipeActionsConfigurationProvider = {[weak self] indexPath in
            // Sections should match, but just in case
            guard let self = self, indexPath.section == self.section else {
                return nil
            }
            return self.swipeActionFor(index: indexPath.item)
        }

        return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
    }

    // MARK: CompositionLayoutCapable

    private func swipeActionFor(index: Int) -> UISwipeActionsConfiguration? {
        let action = UIContextualAction(style: .destructive, title: "Delete") {[weak self] _, _, block in
            self?.deleteItem(index: index, block: block)
        }
        return UISwipeActionsConfiguration(actions: [action])
    }

    private func deleteItem(index: Int, block: @escaping (Bool) -> Void) {
        self.collectionContext.performBatch(animated: true) {updates in
            self.items.remove(at: index)
            updates.delete(in: self, at: IndexSet(integer: index))
        } completion: { completed in
            block(completed)
        }
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/UserComposableSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class UserComposableSectionController: ListSectionController, CompositionLayoutCapable {

    private var user: User?

    override func sizeForItem(at index: Int) -> CGSize {
        // Size handled by cell
        return CGSize.zero
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell: DetailLabelCell = collectionContext.dequeueReusableCell(
            for: self,
            at: index
        )
        cell.title = user?.name
        cell.detail = "@" + (user?.handle ?? "")
        return cell
    }

    override func didUpdate(to object: Any) {
        self.user = object as? User
    }

    // MARK: CompositionLayoutCapable

    func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? {
        let config = UICollectionLayoutListConfiguration(appearance: .plain)
        return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/SectionControllers/WorkingRangeSectionController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class WorkingRangeSectionController: ListSectionController, ListWorkingRangeDelegate {

    private var height: Int?
    private var downloadedImage: UIImage?
    private var task: URLSessionDataTask?

    private var urlString: String? {
        guard let height = height,
              let size = collectionContext?.containerSize
            else { return nil }
        let width = Int(size.width)
        return "https://unsplash.it/" + width.description + "/" + height.description
    }

    deinit {
        task?.cancel()
    }

    override init() {
        super.init()
        workingRangeDelegate = self
    }

    override func numberOfItems() -> Int {
        return 2
    }

    override func sizeForItem(at index: Int) -> CGSize {
        let width: CGFloat = collectionContext?.containerSize.width ?? 0
        let height: CGFloat = CGFloat(index == 0 ? 55 : (self.height ?? 0))
        return CGSize(width: width, height: height)
    }

    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cellClass: UICollectionViewCell.Type = index == 0 ? LabelCell.self : ImageCell.self
        let cell = collectionContext.dequeueReusableCell(of: cellClass, for: self, at: index)
        if let cell = cell as? LabelCell {
            cell.text = urlString
        } else if let cell = cell as? ImageCell {
            cell.setImage(image: downloadedImage)
        }
        return cell
    }

    override func didUpdate(to object: Any) {
        self.height = object as? Int
    }

    // MARK: ListWorkingRangeDelegate

    func listAdapter(_ listAdapter: ListAdapter, sectionControllerWillEnterWorkingRange sectionController: ListSectionController) {
        guard downloadedImage == nil,
            task == nil,
            let urlString = urlString,
            let url = URL(string: urlString)
            else { return }

        print("Downloading image \(urlString) for section \(self.section)")

        task = URLSession.shared.dataTask(with: url) { data, _, error in
            guard let data = data, let image = UIImage(data: data) else {
                return print("Error downloading \(urlString): " + String(describing: error))
            }
            DispatchQueue.main.async {
                self.downloadedImage = image
                if let cell = self.collectionContext?.cellForItem(at: 1, sectionController: self) as? ImageCell {
                    cell.setImage(image: image)
                }
            }
        }
        task?.resume()
    }

    func listAdapter(_ listAdapter: ListAdapter, sectionControllerDidExitWorkingRange sectionController: ListSectionController) {}

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Storyboard/Demo.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Storyboard View Controller-->
        <scene sceneID="oB3-c8-g1U">
            <objects>
                <viewController storyboardIdentifier="demo" id="5n3-mX-NaJ" customClass="StoryboardViewController" customModule="IGListKitExamples" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="VEL-Rj-Wcy"/>
                        <viewControllerLayoutGuide type="bottom" id="wYR-29-GPY"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="s2P-10-T78">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="LKS-vo-Ytk">
                                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <collectionViewLayout key="collectionViewLayout" id="fUa-Xb-tfX" customClass="IGListCollectionViewLayout"/>
                                <cells>
                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="Eqn-FQ-8Sv" customClass="StoryboardCell" customModule="IGListKitExamples" customModuleProvider="target">
                                        <rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                        <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"/>
                                            <subviews>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="6" translatesAutoresizingMaskIntoConstraints="NO" id="1vx-C5-AAO">
                                                    <rect key="frame" x="5" y="18" width="40" height="15"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="12"/>
                                                    <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                            </subviews>
                                        </view>
                                        <color key="backgroundColor" red="0.8912609816" green="0.35455638169999998" blue="0.39968371390000001" alpha="1" colorSpace="calibratedRGB"/>
                                        <constraints>
                                            <constraint firstAttribute="trailing" secondItem="1vx-C5-AAO" secondAttribute="trailing" constant="5" id="IUH-Vl-wp7"/>
                                            <constraint firstItem="1vx-C5-AAO" firstAttribute="leading" secondItem="Eqn-FQ-8Sv" secondAttribute="leading" constant="5" id="Mex-qB-ubM"/>
                                            <constraint firstItem="1vx-C5-AAO" firstAttribute="centerY" secondItem="Eqn-FQ-8Sv" secondAttribute="centerY" id="jSJ-a7-q5U"/>
                                        </constraints>
                                        <connections>
                                            <outlet property="textLabel" destination="1vx-C5-AAO" id="QUu-x5-Hgm"/>
                                        </connections>
                                    </collectionViewCell>
                                </cells>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="LKS-vo-Ytk" firstAttribute="top" secondItem="s2P-10-T78" secondAttribute="top" id="IQP-dj-gaM"/>
                            <constraint firstItem="LKS-vo-Ytk" firstAttribute="leading" secondItem="s2P-10-T78" secondAttribute="leading" id="cc8-Hj-dNE"/>
                            <constraint firstAttribute="bottom" secondItem="LKS-vo-Ytk" secondAttribute="bottom" id="hhH-sV-DXp"/>
                            <constraint firstAttribute="trailing" secondItem="LKS-vo-Ytk" secondAttribute="trailing" id="tnZ-7G-n7P"/>
                        </constraints>
                    </view>
                    <connections>
                        <outlet property="collectionView" destination="LKS-vo-Ytk" id="rhv-M3-HDp"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="WwB-xb-Qef" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-146.40000000000001" y="90.404797601199405"/>
        </scene>
        <!--Single Section Storyboard View Controller-->
        <scene sceneID="VLx-Fb-fo0">
            <objects>
                <viewController storyboardIdentifier="singleSectionDemo" id="frc-YL-WX9" customClass="SingleSectionStoryboardViewController" customModule="IGListKitExamples" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="VaC-h1-D9B"/>
                        <viewControllerLayoutGuide type="bottom" id="jSR-p6-C72"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="bMx-bC-IhF">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="Lqf-9C-lS3">
                                <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="vuu-gE-rAa">
                                    <size key="itemSize" width="309" height="65"/>
                                    <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>
                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="fD7-7i-CX0" customClass="StoryboardCell" customModule="IGListKitExamples" customModuleProvider="target">
                                        <rect key="frame" x="33" y="0.0" width="309" height="65"/>
                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                        <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                            <rect key="frame" x="0.0" y="0.0" width="309" height="65"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <subviews>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y2N-aR-93q">
                                                    <rect key="frame" x="15" y="22" width="42" height="21"/>
                                                    <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
                                                    <nil key="textColor"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                            </subviews>
                                        </view>
                                        <constraints>
                                            <constraint firstItem="y2N-aR-93q" firstAttribute="leading" secondItem="fD7-7i-CX0" secondAttribute="leading" constant="15" id="kVn-2C-bNo"/>
                                            <constraint firstItem="y2N-aR-93q" firstAttribute="centerY" secondItem="fD7-7i-CX0" secondAttribute="centerY" id="zXx-Fd-B4q"/>
                                        </constraints>
                                        <connections>
                                            <outlet property="textLabel" destination="y2N-aR-93q" id="SPh-KG-DJQ"/>
                                        </connections>
                                    </collectionViewCell>
                                </cells>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                        <constraints>
                            <constraint firstItem="Lqf-9C-lS3" firstAttribute="leading" secondItem="bMx-bC-IhF" secondAttribute="leading" id="2B9-1H-mjw"/>
                            <constraint firstItem="Lqf-9C-lS3" firstAttribute="top" secondItem="bMx-bC-IhF" secondAttribute="top" id="4rw-Vn-NT0"/>
                            <constraint firstAttribute="trailing" secondItem="Lqf-9C-lS3" secondAttribute="trailing" id="6St-9C-UOf"/>
                            <constraint firstAttribute="bottom" secondItem="Lqf-9C-lS3" secondAttribute="bottom" id="Hwt-35-Ha0"/>
                        </constraints>
                    </view>
                    <connections>
                        <outlet property="collectionView" destination="Lqf-9C-lS3" id="me8-q7-8f5"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="T5T-i5-O9g" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-825" y="90"/>
        </scene>
    </scenes>
</document>


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/Systems/IncrementAnnouncer.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import UIKit

@objc protocol IncrementListener: AnyObject {
    func didIncrement(announcer: IncrementAnnouncer, value: Int)
}

final class IncrementAnnouncer: NSObject {

    private var value: Int = 0
    private let map: NSHashTable<IncrementListener> = NSHashTable<IncrementListener>.weakObjects()

    func addListener(listener: IncrementListener) {
        map.add(listener)
    }

    func increment() {
        value += 1
        for listener in map.allObjects {
            listener.didIncrement(announcer: self, value: value)
        }
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/ViewControllers/AnnouncingDepsViewController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class AnnouncingDepsViewController: UIViewController, ListAdapterDataSource {

    lazy var adapter: ListAdapter = {
        return ListAdapter(updater: ListAdapterUpdater(), viewController: self, workingRangeSize: 1)
    }()
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
    let data: [NSNumber] = Array(0..<20).map { NSNumber(value: $0) }
    let announcer = IncrementAnnouncer()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(collectionView)
        adapter.collectionView = collectionView
        adapter.dataSource = self

        // disable prefetching so cells are configured as they come on screen
        if #available(iOS 10.0, *) {
            collectionView.isPrefetchingEnabled = false
        }

        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add,
                                                            target: self,
                                                            action: #selector(AnnouncingDepsViewController.onAdd))
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.frame = view.bounds
    }

    @objc func onAdd() {
        announcer.increment()
    }

    // MARK: ListAdapterDataSource

    func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
        return data
    }

    func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
        return ListeningSectionController(announcer: announcer)
    }

    func emptyView(for listAdapter: ListAdapter) -> UIView? {
        return nil
    }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/ViewControllers/CalendarViewController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

final class CalendarViewController: UIViewController, ListAdapterDataSource {

    lazy var adapter: ListAdapter = {
        return ListAdapter(updater: ListAdapterUpdater(), viewController: self)
    }()
    let collectionView = UICollectionView(
        frame: .zero,
        collectionViewLayout: ListCollectionViewLayout(stickyHeaders: false, topContentInset: 0, stretchToEdge: false)
    )

    var months = [Month]()

    override func viewDidLoad() {
        super.viewDidLoad()

        let date = Date()
        let currentMonth = Calendar.current.component(.month, from: date)

        let month = Month(
            name: DateFormatter().monthSymbols[currentMonth - 1],
            days: 30,
            appointments: [
                2: ["Hair"],
                4: ["Nails"],
                7: ["Doctor appt", "Pick up groceries"],
                12: ["Call back the cable company", "Find a babysitter"],
                13: ["Dinner at The Smith"],
                17: ["Buy running shoes", "Buy a fitbit", "Start running"],
                20: ["Call mom"],
                21: ["Contribute to IGListKit"],
                25: ["Interview"],
                26: ["Quit running", "Buy ice cream"]
            ]
        )
        months.append(month)

        view.addSubview(collectionView)
        adapter.collectionView = collectionView
        adapter.dataSource = self
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.frame = view.bounds
    }

    // MARK: ListAdapterDataSource

    func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
        return months
    }

    func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
        return MonthSectionController()
    }

    func emptyView(for listAdapter: ListAdapter) -> UIView? { return nil }

}


================================================
FILE: Examples/Examples-iOS/IGListKitExamples/ViewControllers/CompositionLayoutViewController.swift
================================================
/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import IGListKit
import UIKit

/// Enables SectionControllers to return their own layout. In the future, we might want IGListKit
/// to handle this, but for now, lets keep it simple.
protocol CompositionLayoutCapable {
    func collectionViewSectionLayout(layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection?
}

/// Like MixedDataViewController, but using UICollectionViewCompositionalLayout
final class CompositionLayoutViewController: UIViewController, ListAdapterDataSource {

    private var collectionView: UICollectionView?

    private lazy var adapter: ListAdapter = {
        return ListAdapter(updater: ListAdapterUpdater(), viewController: self)
    }()

    private let data: [Any] = [
        ActivityItem(bodyText: "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", header: "Activity Start"),
        ActivityI
Download .txt
gitextract_na4i75rs/

├── .github/
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── RELEASE_CHECKLIST.md
│   └── workflows/
│       └── CI.yml
├── .gitignore
├── .slather.yml
├── .swiftlint.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dangerfile
├── Examples/
│   ├── Examples-iOS/
│   │   ├── IGListKitExamples/
│   │   │   ├── AppDelegate.swift
│   │   │   ├── Assets.xcassets/
│   │   │   │   └── AppIcon.appiconset/
│   │   │   │       └── Contents.json
│   │   │   ├── Base.lproj/
│   │   │   │   └── LaunchScreen.storyboard
│   │   │   ├── DelegateProtocols/
│   │   │   │   └── PostSectionControllerDelegate.swift
│   │   │   ├── Extensions/
│   │   │   │   ├── UIActivityIndicatorView+Extension.swift
│   │   │   │   └── UIColor+Extension.swift
│   │   │   ├── IGListKitExamples.entitlements
│   │   │   ├── Info.plist
│   │   │   ├── Models/
│   │   │   │   ├── APIService.swift
│   │   │   │   ├── ActivityItem.swift
│   │   │   │   ├── FeedItem.swift
│   │   │   │   ├── GridItem.swift
│   │   │   │   ├── HorizontalCardsSection.swift
│   │   │   │   ├── LoadingCellModel.swift
│   │   │   │   ├── Month.swift
│   │   │   │   ├── Post.h
│   │   │   │   ├── Post.m
│   │   │   │   ├── PostModel.swift
│   │   │   │   ├── RemodelGeneratedModels/
│   │   │   │   │   ├── PersonModel.h
│   │   │   │   │   ├── PersonModel.m
│   │   │   │   │   └── PersonModel.value
│   │   │   │   ├── SelectionModel.swift
│   │   │   │   ├── SwipeActionSection.swift
│   │   │   │   ├── User.swift
│   │   │   │   └── ViewModels/
│   │   │   │       ├── DayViewModel.swift
│   │   │   │       └── MonthTitleViewModel.swift
│   │   │   ├── SectionControllers/
│   │   │   │   ├── DemoSectionController.swift
│   │   │   │   ├── DisplaySectionController.swift
│   │   │   │   ├── EmbeddedSectionController.swift
│   │   │   │   ├── ExpandableSectionController.swift
│   │   │   │   ├── FeedItemSectionController.swift
│   │   │   │   ├── GridSectionController.swift
│   │   │   │   ├── HorizontalSectionController.swift
│   │   │   │   ├── LabelSectionController.swift
│   │   │   │   ├── ListeningSectionController.swift
│   │   │   │   ├── LoadingSectionController.swift
│   │   │   │   ├── MonthSectionController.swift
│   │   │   │   ├── PersonSectionController.h
│   │   │   │   ├── PersonSectionController.m
│   │   │   │   ├── PostSectionController.h
│   │   │   │   ├── PostSectionController.m
│   │   │   │   ├── PostSectionController.swift
│   │   │   │   ├── RemoveSectionController.swift
│   │   │   │   ├── ReorderableSectionController.swift
│   │   │   │   ├── SearchSectionController.swift
│   │   │   │   ├── SelfSizingSectionController.swift
│   │   │   │   ├── StoryboardLabelSectionController.swift
│   │   │   │   ├── UserSectionController.swift
│   │   │   │   ├── With Composable Layout/
│   │   │   │   │   ├── ActivityComposableSectionController.swift
│   │   │   │   │   ├── ExpandableComposableSectionController.swift
│   │   │   │   │   ├── GridComposableSectionController.swift
│   │   │   │   │   ├── HorizontalComposableSectionController.swift
│   │   │   │   │   ├── SelectionComposableSectionController.swift
│   │   │   │   │   ├── SwipeActionComposabelSectionController.swift
│   │   │   │   │   └── UserComposableSectionController.swift
│   │   │   │   └── WorkingRangeSectionController.swift
│   │   │   ├── Storyboard/
│   │   │   │   └── Demo.storyboard
│   │   │   ├── Systems/
│   │   │   │   └── IncrementAnnouncer.swift
│   │   │   ├── ViewControllers/
│   │   │   │   ├── AnnouncingDepsViewController.swift
│   │   │   │   ├── CalendarViewController.swift
│   │   │   │   ├── CompositionLayoutViewController.swift
│   │   │   │   ├── DemosViewController.swift
│   │   │   │   ├── DiffTableViewController.swift
│   │   │   │   ├── DisplayViewController.swift
│   │   │   │   ├── EmptyViewController.swift
│   │   │   │   ├── FeedViewController.swift
│   │   │   │   ├── IGListKitExamples-Bridging-Header.h
│   │   │   │   ├── LoadMoreViewController.swift
│   │   │   │   ├── MixedDataViewController.swift
│   │   │   │   ├── NestedAdapterViewController.swift
│   │   │   │   ├── ObjcDemoViewController.h
│   │   │   │   ├── ObjcDemoViewController.m
│   │   │   │   ├── ObjcGeneratedModelDemoViewController.h
│   │   │   │   ├── ObjcGeneratedModelDemoViewController.m
│   │   │   │   ├── ReorderableViewController.swift
│   │   │   │   ├── SearchViewController.swift
│   │   │   │   ├── SelfSizingCellsViewController.swift
│   │   │   │   ├── SingleSectionStoryboardViewController.swift
│   │   │   │   ├── SingleSectionViewController.swift
│   │   │   │   ├── StoryboardViewController.swift
│   │   │   │   ├── SupplementaryViewController.swift
│   │   │   │   └── WorkingRangeViewController.swift
│   │   │   └── Views/
│   │   │       ├── CalendarDayCell.swift
│   │   │       ├── CenterLabelCell.swift
│   │   │       ├── CommentCell.h
│   │   │       ├── CommentCell.m
│   │   │       ├── CompositionLayoutCell.swift
│   │   │       ├── DetailLabelCell.swift
│   │   │       ├── EmbeddedCollectionViewCell.swift
│   │   │       ├── FullWidthSelfSizingCell.swift
│   │   │       ├── ImageCell.swift
│   │   │       ├── InteractiveCell.h
│   │   │       ├── InteractiveCell.m
│   │   │       ├── LabelCell.swift
│   │   │       ├── LoadingCell.swift
│   │   │       ├── ManuallySelfSizingCell.swift
│   │   │       ├── MonthTitleCell.swift
│   │   │       ├── NibCell.swift
│   │   │       ├── NibCell.xib
│   │   │       ├── NibSelfSizingCell.swift
│   │   │       ├── NibSelfSizingCell.xib
│   │   │       ├── PersonCell.h
│   │   │       ├── PersonCell.m
│   │   │       ├── PhotoCell.h
│   │   │       ├── PhotoCell.m
│   │   │       ├── PostCell.swift
│   │   │       ├── RemoveCell.swift
│   │   │       ├── SearchCell.swift
│   │   │       ├── SpinnerCell.swift
│   │   │       ├── StoryboardCell.swift
│   │   │       ├── UserFooterView.swift
│   │   │       ├── UserFooterView.xib
│   │   │       ├── UserHeaderView.swift
│   │   │       ├── UserHeaderView.xib
│   │   │       ├── UserInfoCell.h
│   │   │       └── UserInfoCell.m
│   │   ├── IGListKitExamples-UITests/
│   │   │   ├── DemosViewControllerUITests.swift
│   │   │   ├── FeedViewController.swift
│   │   │   ├── Info.plist
│   │   │   ├── LoadMoreViewControllerUITests.swift
│   │   │   ├── MixedDataViewControllerUITests.swift
│   │   │   ├── SearchViewControllerUITests.swift
│   │   │   └── UITestCase.swift
│   │   ├── IGListKitExamples.xcodeproj/
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata/
│   │   │       └── xcschemes/
│   │   │           ├── IGListKitExamples.xcscheme
│   │   │           ├── IGListKitMessageExample.xcscheme
│   │   │           └── IGListKitTodayExample.xcscheme
│   │   ├── IGListKitMessageExample/
│   │   │   ├── Assets.xcassets/
│   │   │   │   ├── Contents.json
│   │   │   │   └── iMessage App Icon.stickersiconset/
│   │   │   │       └── Contents.json
│   │   │   ├── Info.plist
│   │   │   └── MessagesViewController.swift
│   │   ├── IGListKitTodayExample/
│   │   │   ├── Info.plist
│   │   │   └── TodayViewController.swift
│   │   └── LICENSE-examples.md
│   ├── Examples-macOS/
│   │   ├── IGListKitExamples/
│   │   │   ├── AppDelegate.swift
│   │   │   ├── Assets.xcassets/
│   │   │   │   └── AppIcon.appiconset/
│   │   │   │       └── Contents.json
│   │   │   ├── Base.lproj/
│   │   │   │   └── Main.storyboard
│   │   │   ├── Data/
│   │   │   │   └── users.json
│   │   │   ├── Helpers/
│   │   │   │   ├── IndexSet+Extensions.swift
│   │   │   │   ├── Shuffle.swift
│   │   │   │   └── UsersProvider.swift
│   │   │   ├── Info.plist
│   │   │   ├── Models/
│   │   │   │   └── User.swift
│   │   │   ├── View/
│   │   │   │   ├── UserCollectionViewCell.swift
│   │   │   │   └── UserCollectionViewCell.xib
│   │   │   └── ViewControllers/
│   │   │       └── UsersViewController.swift
│   │   ├── IGListKitExamples.xcodeproj/
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata/
│   │   │       └── xcschemes/
│   │   │           └── IGListKitExamples.xcscheme
│   │   └── LICENSE-examples.md
│   └── Examples-tvOS/
│       ├── IGListKitExamples/
│       │   ├── AppDelegate.swift
│       │   ├── Assets.xcassets/
│       │   │   ├── App Icon & Top Shelf Image.brandassets/
│       │   │   │   ├── App Icon - Large.imagestack/
│       │   │   │   │   ├── Back.imagestacklayer/
│       │   │   │   │   │   ├── Content.imageset/
│       │   │   │   │   │   │   └── Contents.json
│       │   │   │   │   │   └── Contents.json
│       │   │   │   │   ├── Contents.json
│       │   │   │   │   ├── Front.imagestacklayer/
│       │   │   │   │   │   ├── Content.imageset/
│       │   │   │   │   │   │   └── Contents.json
│       │   │   │   │   │   └── Contents.json
│       │   │   │   │   └── Middle.imagestacklayer/
│       │   │   │   │       ├── Content.imageset/
│       │   │   │   │       │   └── Contents.json
│       │   │   │   │       └── Contents.json
│       │   │   │   ├── App Icon - Small.imagestack/
│       │   │   │   │   ├── Back.imagestacklayer/
│       │   │   │   │   │   ├── Content.imageset/
│       │   │   │   │   │   │   └── Contents.json
│       │   │   │   │   │   └── Contents.json
│       │   │   │   │   ├── Contents.json
│       │   │   │   │   ├── Front.imagestacklayer/
│       │   │   │   │   │   ├── Content.imageset/
│       │   │   │   │   │   │   └── Contents.json
│       │   │   │   │   │   └── Contents.json
│       │   │   │   │   └── Middle.imagestacklayer/
│       │   │   │   │       ├── Content.imageset/
│       │   │   │   │       │   └── Contents.json
│       │   │   │   │       └── Contents.json
│       │   │   │   ├── Contents.json
│       │   │   │   ├── Top Shelf Image Wide.imageset/
│       │   │   │   │   └── Contents.json
│       │   │   │   └── Top Shelf Image.imageset/
│       │   │   │       └── Contents.json
│       │   │   ├── Contents.json
│       │   │   └── LaunchImage.launchimage/
│       │   │       └── Contents.json
│       │   ├── Info.plist
│       │   ├── Models/
│       │   │   └── NSObject+IGListDiffable.swift
│       │   ├── SectionControllers/
│       │   │   ├── CarouselSectionController.swift
│       │   │   ├── DemoSectionController.swift
│       │   │   ├── HorizontalSectionController.swift
│       │   │   └── LabelSectionController.swift
│       │   ├── ViewControllers/
│       │   │   ├── DemosViewController.swift
│       │   │   └── NestedAdapterViewController.swift
│       │   └── Views/
│       │       ├── CarouselCell.swift
│       │       ├── CarouselCell.xib
│       │       ├── DemoCell.swift
│       │       ├── EmbeddedCollectionViewCell.swift
│       │       └── LabelCell.swift
│       ├── IGListKitExamples.xcodeproj/
│       │   ├── project.pbxproj
│       │   └── xcshareddata/
│       │       └── xcschemes/
│       │           └── IGListKitExamples.xcscheme
│       └── LICENSE-examples.md
├── Gemfile
├── Guides/
│   ├── Best Practices and FAQ.md
│   ├── Generating your models using remodel.md
│   ├── Getting Started.md
│   ├── IGListDiffable and Equality.md
│   ├── Installation.md
│   ├── Migration.md
│   ├── Modeling and Binding.md
│   ├── VISION.md
│   ├── Working with Core Data.md
│   └── Working with UICollectionView.md
├── IGListDiffKit.podspec
├── IGListKit.podspec
├── IGListKit.xcodeproj/
│   ├── project.pbxproj
│   └── xcshareddata/
│       └── xcschemes/
│           ├── IGListKit-macOS.xcscheme
│           ├── IGListKit-tvOS.xcscheme
│           └── IGListKit.xcscheme
├── IGListSwiftKit.podspec
├── LICENSE.md
├── Package.swift
├── README.md
├── README.zh.md
├── Source/
│   ├── IGListDiffKit/
│   │   ├── IGListAssert.h
│   │   ├── IGListBatchUpdateData.h
│   │   ├── IGListBatchUpdateData.mm
│   │   ├── IGListCompatibility.h
│   │   ├── IGListDiff.h
│   │   ├── IGListDiff.mm
│   │   ├── IGListDiffKit.h
│   │   ├── IGListDiffable.h
│   │   ├── IGListExperiments.h
│   │   ├── IGListIndexPathResult.h
│   │   ├── IGListIndexPathResult.m
│   │   ├── IGListIndexSetResult.h
│   │   ├── IGListIndexSetResult.m
│   │   ├── IGListMacros.h
│   │   ├── IGListMoveIndex.h
│   │   ├── IGListMoveIndex.m
│   │   ├── IGListMoveIndexPath.h
│   │   ├── IGListMoveIndexPath.m
│   │   ├── Internal/
│   │   │   ├── IGListIndexPathResultInternal.h
│   │   │   ├── IGListIndexSetResultInternal.h
│   │   │   ├── IGListMoveIndexInternal.h
│   │   │   └── IGListMoveIndexPathInternal.h
│   │   ├── NSNumber+IGListDiffable.h
│   │   ├── NSNumber+IGListDiffable.m
│   │   ├── NSString+IGListDiffable.h
│   │   └── NSString+IGListDiffable.m
│   ├── IGListKit/
│   │   ├── IGListAdapter.h
│   │   ├── IGListAdapter.m
│   │   ├── IGListAdapterDataSource.h
│   │   ├── IGListAdapterDelegate.h
│   │   ├── IGListAdapterDelegateAnnouncer.h
│   │   ├── IGListAdapterDelegateAnnouncer.m
│   │   ├── IGListAdapterMoveDelegate.h
│   │   ├── IGListAdapterPerformanceDelegate.h
│   │   ├── IGListAdapterUpdateListener.h
│   │   ├── IGListAdapterUpdater.h
│   │   ├── IGListAdapterUpdater.m
│   │   ├── IGListAdapterUpdaterDelegate.h
│   │   ├── IGListBatchContext.h
│   │   ├── IGListBindable.h
│   │   ├── IGListBindingSectionController.h
│   │   ├── IGListBindingSectionController.m
│   │   ├── IGListBindingSectionControllerDataSource.h
│   │   ├── IGListBindingSectionControllerSelectionDelegate.h
│   │   ├── IGListBindingSingleSectionController.h
│   │   ├── IGListBindingSingleSectionController.m
│   │   ├── IGListCollectionContext.h
│   │   ├── IGListCollectionScrollingTraits.h
│   │   ├── IGListCollectionView.h
│   │   ├── IGListCollectionView.m
│   │   ├── IGListCollectionViewDelegateLayout.h
│   │   ├── IGListCollectionViewLayout.h
│   │   ├── IGListCollectionViewLayout.mm
│   │   ├── IGListCollectionViewLayoutCompatible.h
│   │   ├── IGListCollectionViewLayoutInvalidationContext.h
│   │   ├── IGListCollectionViewLayoutInvalidationContext.m
│   │   ├── IGListDisplayDelegate.h
│   │   ├── IGListGenericSectionController.h
│   │   ├── IGListGenericSectionController.m
│   │   ├── IGListKit.h
│   │   ├── IGListReloadDataUpdater.h
│   │   ├── IGListReloadDataUpdater.m
│   │   ├── IGListScrollDelegate.h
│   │   ├── IGListSectionController.h
│   │   ├── IGListSectionController.m
│   │   ├── IGListSingleSectionController.h
│   │   ├── IGListSingleSectionController.m
│   │   ├── IGListSupplementaryViewSource.h
│   │   ├── IGListTransitionData.h
│   │   ├── IGListTransitionData.m
│   │   ├── IGListTransitionDelegate.h
│   │   ├── IGListUpdatingDelegate.h
│   │   ├── IGListWorkingRangeDelegate.h
│   │   ├── Internal/
│   │   │   ├── IGListAdapter+DebugDescription.h
│   │   │   ├── IGListAdapter+DebugDescription.m
│   │   │   ├── IGListAdapter+UICollectionView.h
│   │   │   ├── IGListAdapter+UICollectionView.m
│   │   │   ├── IGListAdapterDelegateAnnouncerInternal.h
│   │   │   ├── IGListAdapterInternal.h
│   │   │   ├── IGListAdapterProxy.h
│   │   │   ├── IGListAdapterProxy.m
│   │   │   ├── IGListAdapterUpdater+DebugDescription.h
│   │   │   ├── IGListAdapterUpdater+DebugDescription.m
│   │   │   ├── IGListAdapterUpdaterHelpers.h
│   │   │   ├── IGListAdapterUpdaterHelpers.m
│   │   │   ├── IGListAdapterUpdaterInternal.h
│   │   │   ├── IGListArrayUtilsInternal.h
│   │   │   ├── IGListArrayUtilsInternal.m
│   │   │   ├── IGListBatchUpdateData+DebugDescription.h
│   │   │   ├── IGListBatchUpdateData+DebugDescription.m
│   │   │   ├── IGListBatchUpdateState.h
│   │   │   ├── IGListBatchUpdateTransaction.h
│   │   │   ├── IGListBatchUpdateTransaction.m
│   │   │   ├── IGListBindingSectionController+DebugDescription.h
│   │   │   ├── IGListBindingSectionController+DebugDescription.m
│   │   │   ├── IGListCollectionViewLayoutInternal.h
│   │   │   ├── IGListDataSourceChangeTransaction.h
│   │   │   ├── IGListDataSourceChangeTransaction.m
│   │   │   ├── IGListDebugger.h
│   │   │   ├── IGListDebugger.m
│   │   │   ├── IGListDebuggingUtilities.h
│   │   │   ├── IGListDebuggingUtilities.m
│   │   │   ├── IGListDefaultExperiments.h
│   │   │   ├── IGListDisplayHandler.h
│   │   │   ├── IGListDisplayHandler.m
│   │   │   ├── IGListItemUpdatesCollector.h
│   │   │   ├── IGListItemUpdatesCollector.m
│   │   │   ├── IGListPerformDiff.h
│   │   │   ├── IGListPerformDiff.m
│   │   │   ├── IGListReloadIndexPath.h
│   │   │   ├── IGListReloadIndexPath.m
│   │   │   ├── IGListReloadTransaction.h
│   │   │   ├── IGListReloadTransaction.m
│   │   │   ├── IGListSectionControllerInternal.h
│   │   │   ├── IGListSectionMap+DebugDescription.h
│   │   │   ├── IGListSectionMap+DebugDescription.m
│   │   │   ├── IGListSectionMap.h
│   │   │   ├── IGListSectionMap.m
│   │   │   ├── IGListUpdateCoalescer.h
│   │   │   ├── IGListUpdateCoalescer.m
│   │   │   ├── IGListUpdateTransactable.h
│   │   │   ├── IGListUpdateTransactionBuilder.h
│   │   │   ├── IGListUpdateTransactionBuilder.m
│   │   │   ├── IGListViewVisibilityTracker.h
│   │   │   ├── IGListViewVisibilityTracker.m
│   │   │   ├── IGListViewVisibilityTrackerInternal.h
│   │   │   ├── IGListWorkingRangeHandler.h
│   │   │   ├── IGListWorkingRangeHandler.mm
│   │   │   ├── UICollectionView+DebugDescription.h
│   │   │   ├── UICollectionView+DebugDescription.m
│   │   │   ├── UICollectionView+IGListBatchUpdateData.h
│   │   │   ├── UICollectionView+IGListBatchUpdateData.m
│   │   │   ├── UICollectionViewLayout+InteractiveReordering.h
│   │   │   ├── UICollectionViewLayout+InteractiveReordering.m
│   │   │   ├── UIScrollView+IGListKit.h
│   │   │   ├── UIScrollView+IGListKit.m
│   │   │   └── UIViewController+IGListAdapterInternal.h
│   │   ├── UIViewController+IGListAdapter.h
│   │   └── UIViewController+IGListAdapter.m
│   ├── IGListSwiftKit/
│   │   ├── IGListAdapter+Async.swift
│   │   ├── IGListCollectionContext+Refinements.swift
│   │   ├── IGListSingleSectionController+Refinements.swift
│   │   ├── IGListSwiftKit.h
│   │   ├── ListIdentifiable.swift
│   │   └── ListValueSectionController.swift
│   └── Info.plist
├── Tests/
│   ├── Assets/
│   │   ├── IGTestNibCell.xib
│   │   ├── IGTestNibSupplementaryView.xib
│   │   └── IGTestStoryboard.storyboard
│   ├── IGListAdapterDelegateAnnouncerTests.m
│   ├── IGListAdapterE2ETests.m
│   ├── IGListAdapterProxyTests.m
│   ├── IGListAdapterStoryboardTests.m
│   ├── IGListAdapterTests.m
│   ├── IGListAdapterUpdaterTests.m
│   ├── IGListBatchUpdateDataTests.m
│   ├── IGListBindingSectionControllerTests.m
│   ├── IGListBindingSingleSectionControllerTests.m
│   ├── IGListCollectionScrollingTraitsTests.m
│   ├── IGListCollectionViewLayoutTests.m
│   ├── IGListCollectionViewTests.m
│   ├── IGListContentInsetTests.m
│   ├── IGListDebugDescriptionTests.m
│   ├── IGListDebuggerTests.m
│   ├── IGListDiffDescriptionStringTests.m
│   ├── IGListDiffResultTests.m
│   ├── IGListDiffSwiftTests.swift
│   ├── IGListDiffTests.h
│   ├── IGListDiffTests.m
│   ├── IGListDisplayHandlerTests.m
│   ├── IGListGenericSectionControllerTests.m
│   ├── IGListInteractiveMovingTests.m
│   ├── IGListItemUpdatesCollectorTests.m
│   ├── IGListKitTests-Bridging-Header.h
│   ├── IGListPerformDiffTests.m
│   ├── IGListReloadDataUpdaterTests.m
│   ├── IGListSectionControllerTests.m
│   ├── IGListSectionMapTests.m
│   ├── IGListSingleNibItemControllerTests.m
│   ├── IGListSingleSectionControllerTests.m
│   ├── IGListSingleStoryboardItemControllerTests.m
│   ├── IGListTestCase.h
│   ├── IGListTestCase.m
│   ├── IGListTestHelpers.h
│   ├── IGListTransactionTests.m
│   ├── IGListUpdateCoalescerTests.m
│   ├── IGListViewVisibilityTrackerTests.m
│   ├── IGListWorkingRangeHandlerTests.m
│   ├── Info.plist
│   ├── Objects/
│   │   ├── IGLayoutTestDataSource.h
│   │   ├── IGLayoutTestDataSource.m
│   │   ├── IGLayoutTestItem.h
│   │   ├── IGLayoutTestItem.m
│   │   ├── IGLayoutTestSection.h
│   │   ├── IGLayoutTestSection.m
│   │   ├── IGListAdapterUpdateTester.h
│   │   ├── IGListAdapterUpdateTester.m
│   │   ├── IGListTestAdapterDataSource.h
│   │   ├── IGListTestAdapterDataSource.m
│   │   ├── IGListTestAdapterHorizontalDataSource.h
│   │   ├── IGListTestAdapterHorizontalDataSource.m
│   │   ├── IGListTestAdapterReorderingDataSource.h
│   │   ├── IGListTestAdapterReorderingDataSource.m
│   │   ├── IGListTestAdapterStoryboardDataSource.h
│   │   ├── IGListTestAdapterStoryboardDataSource.m
│   │   ├── IGListTestCollectionViewLayout.h
│   │   ├── IGListTestCollectionViewLayout.m
│   │   ├── IGListTestContainerSizeSection.h
│   │   ├── IGListTestContainerSizeSection.m
│   │   ├── IGListTestHorizontalSection.h
│   │   ├── IGListTestHorizontalSection.m
│   │   ├── IGListTestOffsettingLayout.h
│   │   ├── IGListTestOffsettingLayout.m
│   │   ├── IGListTestSection.h
│   │   ├── IGListTestSection.m
│   │   ├── IGListTestStoryboardSection.h
│   │   ├── IGListTestStoryboardSection.m
│   │   ├── IGListTestUICollectionViewDataSource.h
│   │   ├── IGListTestUICollectionViewDataSource.m
│   │   ├── IGTestBindingSingleItemDataSource.h
│   │   ├── IGTestBindingSingleItemDataSource.m
│   │   ├── IGTestBindingWithoutDeselectionDelegate.h
│   │   ├── IGTestBindingWithoutDeselectionDelegate.m
│   │   ├── IGTestCell.h
│   │   ├── IGTestCell.m
│   │   ├── IGTestDelegateController.h
│   │   ├── IGTestDelegateController.m
│   │   ├── IGTestDelegateDataSource.h
│   │   ├── IGTestDelegateDataSource.m
│   │   ├── IGTestDiffingDataSource.h
│   │   ├── IGTestDiffingDataSource.m
│   │   ├── IGTestDiffingObject.h
│   │   ├── IGTestDiffingObject.m
│   │   ├── IGTestDiffingSectionController.h
│   │   ├── IGTestDiffingSectionController.m
│   │   ├── IGTestInvalidateLayoutDataSource.h
│   │   ├── IGTestInvalidateLayoutDataSource.m
│   │   ├── IGTestInvalidateLayoutObject.h
│   │   ├── IGTestInvalidateLayoutObject.m
│   │   ├── IGTestInvalidateLayoutSectionController.h
│   │   ├── IGTestInvalidateLayoutSectionController.m
│   │   ├── IGTestNibSupplementaryView.h
│   │   ├── IGTestNibSupplementaryView.m
│   │   ├── IGTestNumberBindableCell.h
│   │   ├── IGTestNumberBindableCell.m
│   │   ├── IGTestObject.h
│   │   ├── IGTestObject.m
│   │   ├── IGTestReorderableSection.h
│   │   ├── IGTestReorderableSection.m
│   │   ├── IGTestSingleItemDataSource.h
│   │   ├── IGTestSingleItemDataSource.m
│   │   ├── IGTestSingleNibItemDataSource.h
│   │   ├── IGTestSingleNibItemDataSource.m
│   │   ├── IGTestSingleStoryboardItemDataSource.h
│   │   ├── IGTestSingleStoryboardItemDataSource.m
│   │   ├── IGTestSingleWithoutDeselectionDelegate.h
│   │   ├── IGTestSingleWithoutDeselectionDelegate.m
│   │   ├── IGTestStoryboardCell.h
│   │   ├── IGTestStoryboardCell.m
│   │   ├── IGTestStoryboardSupplementarySource.h
│   │   ├── IGTestStoryboardSupplementarySource.m
│   │   ├── IGTestStoryboardSupplementaryView.h
│   │   ├── IGTestStoryboardSupplementaryView.m
│   │   ├── IGTestStoryboardViewController.h
│   │   ├── IGTestStoryboardViewController.m
│   │   ├── IGTestStringBindableCell.h
│   │   ├── IGTestStringBindableCell.m
│   │   ├── IGTestSupplementarySource.h
│   │   └── IGTestSupplementarySource.m
│   └── UIViewControllerIGListAdapterTests.m
├── docs/
│   ├── Categories/
│   │   └── UIViewController(IGListAdapter).html
│   ├── Categories.html
│   ├── Classes/
│   │   ├── IGListAdapter.html
│   │   ├── IGListAdapterDelegateAnnouncer.html
│   │   ├── IGListAdapterUpdater.html
│   │   ├── IGListBatchUpdateData.html
│   │   ├── IGListBindingSectionController.html
│   │   ├── IGListBindingSingleSectionController.html
│   │   ├── IGListCollectionView.html
│   │   ├── IGListCollectionViewLayout.html
│   │   ├── IGListCollectionViewLayoutInvalidationContext.html
│   │   ├── IGListGenericSectionController.html
│   │   ├── IGListIndexPathResult.html
│   │   ├── IGListIndexSetResult.html
│   │   ├── IGListMoveIndex.html
│   │   ├── IGListMoveIndexPath.html
│   │   ├── IGListSectionController.html
│   │   ├── IGListSingleSectionController.html
│   │   └── IGListTransitionData.html
│   ├── Classes.html
│   ├── Constants.html
│   ├── Enums/
│   │   ├── IGListAdapterUpdateType.html
│   │   ├── IGListDiffOption.html
│   │   └── IGListExperiment.html
│   ├── Enums.html
│   ├── Functions.html
│   ├── Guides.html
│   ├── Protocols/
│   │   ├── IGListAdapterDataSource.html
│   │   ├── IGListAdapterDelegate.html
│   │   ├── IGListAdapterMoveDelegate.html
│   │   ├── IGListAdapterPerformanceDelegate.html
│   │   ├── IGListAdapterUpdateListener.html
│   │   ├── IGListAdapterUpdaterDelegate.html
│   │   ├── IGListBatchContext.html
│   │   ├── IGListBindable.html
│   │   ├── IGListBindingSectionControllerDataSource.html
│   │   ├── IGListBindingSectionControllerSelectionDelegate.html
│   │   ├── IGListCollectionContext.html
│   │   ├── IGListCollectionViewDelegateLayout.html
│   │   ├── IGListCollectionViewLayoutCompatible.html
│   │   ├── IGListDiffable.html
│   │   ├── IGListDisplayDelegate.html
│   │   ├── IGListScrollDelegate.html
│   │   ├── IGListSingleSectionControllerDelegate.html
│   │   ├── IGListSupplementaryViewSource.html
│   │   ├── IGListTransitionDelegate.html
│   │   ├── IGListUpdatingDelegate.html
│   │   └── IGListWorkingRangeDelegate.html
│   ├── Protocols.html
│   ├── Structs/
│   │   ├── IGListAdaptiveCoalescingExperimentConfig.html
│   │   ├── IGListAdaptiveDiffingExperimentConfig.html
│   │   └── IGListCollectionScrollingTraits.html
│   ├── Structs.html
│   ├── Type Definitions/
│   │   ├── IGListAdaptiveCoalescingExperimentConfig/
│   │   │   └── IGListAdaptiveCoalescingExperimentConfig.html
│   │   ├── IGListAdaptiveCoalescingExperimentConfig.html
│   │   ├── IGListAdaptiveDiffingExperimentConfig/
│   │   │   └── IGListAdaptiveDiffingExperimentConfig.html
│   │   ├── IGListAdaptiveDiffingExperimentConfig.html
│   │   ├── IGListCollectionScrollingTraits/
│   │   │   └── IGListCollectionScrollingTraits.html
│   │   └── IGListCollectionScrollingTraits.html
│   ├── Type Definitions.html
│   ├── best-practices-and-faq.html
│   ├── css/
│   │   ├── highlight.css
│   │   └── jazzy.css
│   ├── generating-your-models-using-remodel.html
│   ├── getting-started.html
│   ├── iglistdiffable-and-equality.html
│   ├── index.html
│   ├── installation.html
│   ├── js/
│   │   ├── jazzy.js
│   │   ├── jazzy.search.js
│   │   └── typeahead.jquery.js
│   ├── migration.html
│   ├── modeling-and-binding.html
│   ├── search.json
│   ├── undocumented.json
│   ├── vision.html
│   ├── working-with-core-data.html
│   └── working-with-uicollectionview.html
├── remodel-plugin/
│   ├── features/
│   │   └── iglistdiffable.feature
│   └── src/
│       ├── __tests__/
│       │   └── plugins/
│       │       └── iglistdiffable-test.ts
│       └── plugins/
│           ├── iglistdiffable-utils.ts
│           └── iglistdiffable.ts
└── scripts/
    ├── build_docs.sh
    ├── generate_spm_sources_layout.sh
    ├── lint.sh
    └── version.sh
Download .txt
SYMBOL INDEX (72 symbols across 14 files)

FILE: Source/IGListDiffKit/IGListExperiments.h
  type IGListAdaptiveDiffingExperimentConfig (line 37) | struct IGListAdaptiveDiffingExperimentConfig {
  type IGListAdaptiveCoalescingExperimentConfig (line 52) | struct IGListAdaptiveCoalescingExperimentConfig {
  function IGListExperimentEnabled (line 73) | NS_SWIFT_NAME(ListExperimentEnabled(mask:option:))

FILE: Source/IGListKit/IGListCollectionScrollingTraits.h
  type IGListCollectionScrollingTraits (line 15) | struct IGListCollectionScrollingTraits {

FILE: Source/IGListKit/Internal/IGListAdapterInternal.h
  function NSString (line 21) | NSString *IGListReusableViewIdentifier(Class viewClass, NSString * _Null...

FILE: Source/IGListKit/Internal/IGListBatchUpdateState.h
  type IGListBatchUpdateStateIdle (line 10) | typedef NS_ENUM (NSInteger, IGListBatchUpdateState) {

FILE: Source/IGListKit/Internal/IGListCollectionViewLayoutInternal.h
  function CGRect (line 10) | static inline CGRect IGListRectIntegralScaled(CGRect rect) {

FILE: Source/IGListKit/Internal/IGListDefaultExperiments.h
  function IGListExperiment (line 17) | static inline IGListExperiment IGListDefaultExperiments(void) {

FILE: Source/IGListKit/Internal/IGListUpdateTransactable.h
  function NS_ASSUME_NONNULL_BEGIN (line 19) | NS_ASSUME_NONNULL_BEGIN

FILE: Tests/IGListTestHelpers.h
  function NSIndexPath (line 10) | static inline NSIndexPath *genIndexPath(NSInteger section, NSInteger ite...

FILE: docs/js/jazzy.js
  function toggleItem (line 15) | function toggleItem($link, $content) {
  function itemLinkToContent (line 21) | function itemLinkToContent($link) {
  function openCurrentItemIfClosed (line 26) | function openCurrentItemIfClosed() {

FILE: docs/js/jazzy.search.js
  function displayTemplate (line 10) | function displayTemplate(result) {
  function suggestionTemplate (line 14) | function suggestionTemplate(result) {

FILE: docs/js/typeahead.jquery.js
  function reverseArgs (line 55) | function reverseArgs(index, value) {
  function template (line 100) | function template() {
  function _p8 (line 153) | function _p8(s) {
  function build (line 178) | function build(o) {
  function buildHtml (line 197) | function buildHtml(c) {
  function buildSelectors (line 203) | function buildSelectors(classes) {
  function buildCss (line 210) | function buildCss() {
  function EventBus (line 267) | function EventBus(o) {
  function on (line 304) | function on(method, types, cb, context) {
  function onAsync (line 321) | function onAsync(types, cb, context) {
  function onSync (line 324) | function onSync(types, cb, context) {
  function off (line 327) | function off(types) {
  function trigger (line 338) | function trigger(types) {
  function getFlush (line 352) | function getFlush(callbacks, context, args) {
  function getNextTick (line 362) | function getNextTick() {
  function bindContext (line 379) | function bindContext(fn, context) {
  function hightlightTextNode (line 433) | function hightlightTextNode(textNode) {
  function traverse (line 445) | function traverse(el, hightlightTextNode) {
  function accent_replacer (line 457) | function accent_replacer(chr) {
  function getRegex (line 460) | function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensiti...
  function Input (line 485) | function Input(o, www) {
  function buildOverflowHelper (line 685) | function buildOverflowHelper($input) {
  function areQueriesEquivalent (line 702) | function areQueriesEquivalent(a, b) {
  function withModifier (line 705) | function withModifier($e) {
  function Dataset (line 718) | function Dataset(o, www) {
  function sync (line 859) | function sync(suggestions) {
  function async (line 871) | function async(suggestions) {
  function getDisplayFn (line 896) | function getDisplayFn(display) {
  function getTemplates (line 903) | function getTemplates(templates, displayFn) {
  function isValidName (line 919) | function isValidName(str) {
  function Menu (line 925) | function Menu(o, www) {
  function updateDataset (line 1047) | function updateDataset(dataset) {
  function clearDataset (line 1055) | function clearDataset(dataset) {
  function destroyDataset (line 1063) | function destroyDataset(dataset) {
  function Status (line 1072) | function Status(options) {
  function DefaultMenu (line 1122) | function DefaultMenu() {
  function Typeahead (line 1165) | function Typeahead(o, www) {
  function c (line 1448) | function c(ctx) {
  function attach (line 1474) | function attach() {
  function ttEach (line 1633) | function ttEach($els, fn) {
  function buildHintFromInput (line 1639) | function buildHintFromInput($input, www) {
  function prepInput (line 1648) | function prepInput($input, www) {
  function getBackgroundStyles (line 1663) | function getBackgroundStyles($el) {
  function revert (line 1675) | function revert($input) {
  function $elOrNull (line 1688) | function $elOrNull(obj) {

FILE: remodel-plugin/src/__tests__/plugins/iglistdiffable-test.ts
  function igListDiffableIsEqualMethod (line 20) | function igListDiffableIsEqualMethod(): ObjC.Method {
  function igListDiffableDiffIdentifierMethodWithCode (line 50) | function igListDiffableDiffIdentifierMethodWithCode(code: string): ObjC....

FILE: remodel-plugin/src/plugins/iglistdiffable-utils.ts
  function isEqualToDiffableObjectMethod (line 14) | function isEqualToDiffableObjectMethod(): ObjC.Method {
  function functionReturnValueForIvarWithFunctionName (line 44) | function functionReturnValueForIvarWithFunctionName(
  function formattedStringValueForIvarWithFormatSpecifier (line 51) | function formattedStringValueForIvarWithFormatSpecifier(
  function nullableObjectValueWithFallback (line 68) | function nullableObjectValueWithFallback(
  function wrappedInNSValueForTypeName (line 77) | function wrappedInNSValueForTypeName(iVarString: string, typeName: strin...
  function objectValueForAttribute (line 81) | function objectValueForAttribute(

FILE: remodel-plugin/src/plugins/iglistdiffable.ts
  function diffIdentiferAttributeFilter (line 16) | function diffIdentiferAttributeFilter(
  function diffIdentifierMethodImplementation (line 24) | function diffIdentifierMethodImplementation(
  function diffIdentifierMethod (line 45) | function diffIdentifierMethod(objectType: ObjectSpec.Type): ObjC.Method {
  function createPlugin (line 68) | function createPlugin(): ObjectSpec.Plugin {
Condensed preview — 574 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,255K chars).
[
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 3435,
    "preview": "# Contributing to IGListKit\n\nWe want to make contributing to this project as easy and transparent as\npossible, and activ"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 704,
    "preview": "## New issue checklist\n\n- [ ] I have reviewed the [`README`](https://github.com/Instagram/IGListKit/blob/main/README.md)"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 412,
    "preview": "## Changes in this pull request\n\nIssue fixed: #\n\n### Checklist\n\n- [ ] All tests pass. Demo project builds and runs.\n- [ "
  },
  {
    "path": ".github/RELEASE_CHECKLIST.md",
    "chars": 817,
    "preview": "# Release Checklist\n\nHere are the steps for creating and publishing a new release for `IGListKit`.\n\n- Final review and u"
  },
  {
    "path": ".github/workflows/CI.yml",
    "chars": 11138,
    "preview": "name: \"IGListKit CI\"\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - '*'\n\njobs:\n  macOS:\n "
  },
  {
    "path": ".gitignore",
    "chars": 1241,
    "preview": ".DS_Store\n\nPodfile.lock\nGemfile.lock\n\n# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Obj"
  },
  {
    "path": ".slather.yml",
    "chars": 193,
    "preview": "ci_service: github\ncoverage_service: coveralls\nxcodeproj: IGListKit.xcodeproj\nworkspace: IGListKit.xcworkspace\nscheme: I"
  },
  {
    "path": ".swiftlint.yml",
    "chars": 823,
    "preview": "included:\n  - Examples\n  - Source/IGListSwiftKit\n\nexcluded:\n  - Pods\n\nopt_in_rules:\n  - empty_count\n  - number_separator"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 57790,
    "preview": "# CHANGELOG\n\nThe changelog for `IGListKit`. Also see the [releases](https://github.com/instagram/IGListKit/releases) on "
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3356,
    "preview": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and"
  },
  {
    "path": "Dangerfile",
    "chars": 2286,
    "preview": "not_declared_trivial = !(github.pr_title.include? \"#trivial\")\nhas_source_changes = !git.modified_files.grep(/Source/).em"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/AppDelegate.swift",
    "chars": 1736,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 211,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon.png\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"s"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Base.lproj/LaunchScreen.storyboard",
    "chars": 2825,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/DelegateProtocols/PostSectionControllerDelegate.swift",
    "chars": 471,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Extensions/UIActivityIndicatorView+Extension.swift",
    "chars": 427,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Extensions/UIColor+Extension.swift",
    "chars": 1654,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/IGListKitExamples.entitlements",
    "chars": 295,
    "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": "Examples/Examples-iOS/IGListKitExamples/Info.plist",
    "chars": 1323,
    "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": "Examples/Examples-iOS/IGListKitExamples/Models/APIService.swift",
    "chars": 2449,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/ActivityItem.swift",
    "chars": 866,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/FeedItem.swift",
    "chars": 854,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/GridItem.swift",
    "chars": 899,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/HorizontalCardsSection.swift",
    "chars": 871,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/LoadingCellModel.swift",
    "chars": 1083,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/Month.swift",
    "chars": 778,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/Post.h",
    "chars": 653,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/Post.m",
    "chars": 744,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/PostModel.swift",
    "chars": 2068,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.h",
    "chars": 836,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.m",
    "chars": 2109,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/RemodelGeneratedModels/PersonModel.value",
    "chars": 122,
    "preview": "PersonModel includes(IGListDiffable) {\n  NSString *firstName\n  NSString *lastName\n  %diffIdentifier\n  NSString *uniqueId"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/SelectionModel.swift",
    "chars": 727,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/SwipeActionSection.swift",
    "chars": 532,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/User.swift",
    "chars": 810,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/ViewModels/DayViewModel.swift",
    "chars": 978,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Models/ViewModels/MonthTitleViewModel.swift",
    "chars": 768,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/DemoSectionController.swift",
    "chars": 3979,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/DisplaySectionController.swift",
    "chars": 1940,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/EmbeddedSectionController.swift",
    "chars": 1096,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/ExpandableSectionController.swift",
    "chars": 1394,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/FeedItemSectionController.swift",
    "chars": 2792,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/GridSectionController.swift",
    "chars": 1706,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/HorizontalSectionController.swift",
    "chars": 1538,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/LabelSectionController.swift",
    "chars": 802,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/ListeningSectionController.swift",
    "chars": 1276,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/LoadingSectionController.swift",
    "chars": 1302,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/MonthSectionController.swift",
    "chars": 4751,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PersonSectionController.h",
    "chars": 278,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PersonSectionController.m",
    "chars": 1018,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.h",
    "chars": 276,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.m",
    "chars": 1740,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/PostSectionController.swift",
    "chars": 2363,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/RemoveSectionController.swift",
    "chars": 1318,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/ReorderableSectionController.swift",
    "chars": 889,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/SearchSectionController.swift",
    "chars": 1973,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/SelfSizingSectionController.swift",
    "chars": 1897,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/StoryboardLabelSectionController.swift",
    "chars": 1234,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/UserSectionController.swift",
    "chars": 1102,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/ActivityComposableSectionController.swift",
    "chars": 5984,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/ExpandableComposableSectionController.swift",
    "chars": 1907,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/GridComposableSectionController.swift",
    "chars": 1969,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/HorizontalComposableSectionController.swift",
    "chars": 2111,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/SelectionComposableSectionController.swift",
    "chars": 4394,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/SwipeActionComposabelSectionController.swift",
    "chars": 2379,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/With Composable Layout/UserComposableSectionController.swift",
    "chars": 1211,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/SectionControllers/WorkingRangeSectionController.swift",
    "chars": 2876,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Storyboard/Demo.storyboard",
    "chars": 12303,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Systems/IncrementAnnouncer.swift",
    "chars": 746,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/AnnouncingDepsViewController.swift",
    "chars": 1918,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/CalendarViewController.swift",
    "chars": 2118,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/CompositionLayoutViewController.swift",
    "chars": 5232,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/DemosViewController.swift",
    "chars": 6277,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/DiffTableViewController.swift",
    "chars": 2998,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/DisplayViewController.swift",
    "chars": 1253,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/EmptyViewController.swift",
    "chars": 2675,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/FeedViewController.swift",
    "chars": 6661,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/IGListKitExamples-Bridging-Header.h",
    "chars": 275,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/LoadMoreViewController.swift",
    "chars": 2927,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/MixedDataViewController.swift",
    "chars": 4909,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/NestedAdapterViewController.swift",
    "chars": 1650,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ObjcDemoViewController.h",
    "chars": 275,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ObjcDemoViewController.m",
    "chars": 3229,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ObjcGeneratedModelDemoViewController.h",
    "chars": 289,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ObjcGeneratedModelDemoViewController.m",
    "chars": 3817,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/ReorderableViewController.swift",
    "chars": 2839,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SearchViewController.swift",
    "chars": 3241,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SelfSizingCellsViewController.swift",
    "chars": 3372,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SingleSectionStoryboardViewController.swift",
    "chars": 2381,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SingleSectionViewController.swift",
    "chars": 2736,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/StoryboardViewController.swift",
    "chars": 2897,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/SupplementaryViewController.swift",
    "chars": 1754,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/ViewControllers/WorkingRangeViewController.swift",
    "chars": 1504,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/CalendarDayCell.swift",
    "chars": 2068,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/CenterLabelCell.swift",
    "chars": 814,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/CommentCell.h",
    "chars": 314,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/CommentCell.m",
    "chars": 1277,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/CompositionLayoutCell.swift",
    "chars": 1949,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/DetailLabelCell.swift",
    "chars": 1440,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/EmbeddedCollectionViewCell.swift",
    "chars": 831,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/FullWidthSelfSizingCell.swift",
    "chars": 2749,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/ImageCell.swift",
    "chars": 1444,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/InteractiveCell.h",
    "chars": 272,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/InteractiveCell.m",
    "chars": 3060,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/LabelCell.swift",
    "chars": 6498,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/LoadingCell.swift",
    "chars": 1249,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/ManuallySelfSizingCell.swift",
    "chars": 2757,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/MonthTitleCell.swift",
    "chars": 1081,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/NibCell.swift",
    "chars": 423,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/NibCell.xib",
    "chars": 4817,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/NibSelfSizingCell.swift",
    "chars": 477,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/NibSelfSizingCell.xib",
    "chars": 4367,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/PersonCell.h",
    "chars": 336,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/PersonCell.m",
    "chars": 3879,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/PhotoCell.h",
    "chars": 266,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/PhotoCell.m",
    "chars": 897,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/PostCell.swift",
    "chars": 10845,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/RemoveCell.swift",
    "chars": 1580,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/SearchCell.swift",
    "chars": 609,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/SpinnerCell.swift",
    "chars": 1196,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/StoryboardCell.swift",
    "chars": 460,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/UserFooterView.swift",
    "chars": 497,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/UserFooterView.xib",
    "chars": 4227,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/UserHeaderView.swift",
    "chars": 672,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/UserHeaderView.xib",
    "chars": 4184,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/UserInfoCell.h",
    "chars": 312,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples/Views/UserInfoCell.m",
    "chars": 1960,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples-UITests/DemosViewControllerUITests.swift",
    "chars": 4006,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples-UITests/FeedViewController.swift",
    "chars": 4413,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples-UITests/Info.plist",
    "chars": 701,
    "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": "Examples/Examples-iOS/IGListKitExamples-UITests/LoadMoreViewControllerUITests.swift",
    "chars": 1027,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples-UITests/MixedDataViewControllerUITests.swift",
    "chars": 3355,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples-UITests/SearchViewControllerUITests.swift",
    "chars": 1583,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples-UITests/UITestCase.swift",
    "chars": 3369,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples.xcodeproj/project.pbxproj",
    "chars": 96204,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme",
    "chars": 3817,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1500\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitMessageExample.xcscheme",
    "chars": 4603,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1500\"\n   wasCreatedForAppExtension = \"YES\"\n   ve"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitTodayExample.xcscheme",
    "chars": 4541,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1500\"\n   wasCreatedForAppExtension = \"YES\"\n   ve"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitMessageExample/Assets.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/Examples-iOS/IGListKitMessageExample/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json",
    "chars": 985,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x45\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\""
  },
  {
    "path": "Examples/Examples-iOS/IGListKitMessageExample/Info.plist",
    "chars": 1001,
    "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": "Examples/Examples-iOS/IGListKitMessageExample/MessagesViewController.swift",
    "chars": 1644,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/IGListKitTodayExample/Info.plist",
    "chars": 988,
    "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": "Examples/Examples-iOS/IGListKitTodayExample/TodayViewController.swift",
    "chars": 1995,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-iOS/LICENSE-examples.md",
    "chars": 637,
    "preview": "Copyright (c) Meta Platforms, Inc. and affiliates.\n\nThe examples provided by Facebook are for non-commercial testing and"
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/AppDelegate.swift",
    "chars": 438,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 903,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : "
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/Base.lproj/Main.storyboard",
    "chars": 67054,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" t"
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/Data/users.json",
    "chars": 4730,
    "preview": "[{\n\t\"name\": \"AMELIA\"\n}, \n{\n\t\"name\": \"OLIVIA\"\n}, \n{\n\t\"name\": \"EMILY\"\n}, \n{\n\t\"name\": \"AVA\"\n}, \n{\n\t\"name\": \"ISLA\"\n}, \n{\n\t\"n"
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/Helpers/IndexSet+Extensions.swift",
    "chars": 321,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/Helpers/Shuffle.swift",
    "chars": 980,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/Helpers/UsersProvider.swift",
    "chars": 837,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/Info.plist",
    "chars": 1032,
    "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": "Examples/Examples-macOS/IGListKitExamples/Models/User.swift",
    "chars": 737,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/View/UserCollectionViewCell.swift",
    "chars": 709,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/View/UserCollectionViewCell.xib",
    "chars": 5916,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion"
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples/ViewControllers/UsersViewController.swift",
    "chars": 5113,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples.xcodeproj/project.pbxproj",
    "chars": 18628,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "Examples/Examples-macOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme",
    "chars": 3901,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1500\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "Examples/Examples-macOS/LICENSE-examples.md",
    "chars": 637,
    "preview": "Copyright (c) Meta Platforms, Inc. and affiliates.\n\nThe examples provided by Facebook are for non-commercial testing and"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/AppDelegate.swift",
    "chars": 686,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json",
    "chars": 137,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json",
    "chars": 250,
    "preview": "{\n  \"layers\" : [\n    {\n      \"filename\" : \"Front.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Middle.imagestacklaye"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json",
    "chars": 137,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json",
    "chars": 137,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json",
    "chars": 137,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json",
    "chars": 250,
    "preview": "{\n  \"layers\" : [\n    {\n      \"filename\" : \"Front.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Middle.imagestacklaye"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json",
    "chars": 137,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json",
    "chars": 137,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json",
    "chars": 667,
    "preview": "{\n  \"assets\" : [\n    {\n      \"size\" : \"1280x768\",\n      \"idiom\" : \"tv\",\n      \"filename\" : \"App Icon - Large.imagestack\""
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json",
    "chars": 137,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json",
    "chars": 137,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Assets.xcassets/LaunchImage.launchimage/Contents.json",
    "chars": 244,
    "preview": "{\n  \"images\" : [\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"tv\",\n      \"extent\" : \"full-screen\",\n      \"m"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Info.plist",
    "chars": 926,
    "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": "Examples/Examples-tvOS/IGListKitExamples/Models/NSObject+IGListDiffable.swift",
    "chars": 459,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/SectionControllers/CarouselSectionController.swift",
    "chars": 1468,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/SectionControllers/DemoSectionController.swift",
    "chars": 2127,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/SectionControllers/HorizontalSectionController.swift",
    "chars": 1814,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/SectionControllers/LabelSectionController.swift",
    "chars": 916,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/ViewControllers/DemosViewController.swift",
    "chars": 1429,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/ViewControllers/NestedAdapterViewController.swift",
    "chars": 1526,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Views/CarouselCell.swift",
    "chars": 688,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Views/CarouselCell.xib",
    "chars": 3083,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder.AppleTV.XIB\" version=\""
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Views/DemoCell.swift",
    "chars": 1077,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Views/EmbeddedCollectionViewCell.swift",
    "chars": 901,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples/Views/LabelCell.swift",
    "chars": 2000,
    "preview": "/*\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found "
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples.xcodeproj/project.pbxproj",
    "chars": 20985,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "Examples/Examples-tvOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme",
    "chars": 3317,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1500\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "Examples/Examples-tvOS/LICENSE-examples.md",
    "chars": 637,
    "preview": "Copyright (c) Meta Platforms, Inc. and affiliates.\n\nThe examples provided by Facebook are for non-commercial testing and"
  },
  {
    "path": "Gemfile",
    "chars": 174,
    "preview": "source 'https://rubygems.org'\n\ngem 'cocoapods', '~> 1.16.2'\ngem 'danger', '~> 9.3.1'\ngem 'danger-swiftlint', '~> 0.33.0'"
  },
  {
    "path": "Guides/Best Practices and FAQ.md",
    "chars": 8761,
    "preview": "# Best Practices and FAQs\n\nThis guide provides notes and details on best practices in using `IGListKit`, general tips, a"
  },
  {
    "path": "Guides/Generating your models using remodel.md",
    "chars": 4903,
    "preview": "# Generating your IGListDiffable models using remodel\n\nWith the `IGListDiffable` plugin for [remodel by facebook](https:"
  },
  {
    "path": "Guides/Getting Started.md",
    "chars": 7253,
    "preview": "# Getting Started\n\nThis guide provides a brief overview for how to get started using `IGListKit`.\n\n## Creating your firs"
  }
]

// ... and 374 more files (download for full content)

About this extraction

This page contains the full source code of the Instagram/IGListKit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 574 files (4.8 MB), approximately 1.3M tokens, and a symbol index with 72 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!