<commit_before>import UIKit
import MediaPlayer
import MobileCoreServices

class ShowViewController: UITableViewController {
    
    private let engine = Engine.shared
    private var editedIndexPath: IndexPath?
    
    @IBOutlet weak var editBarButtonItem: UIBarButtonItem!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.rightBarButtonItem = editButtonItem
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        if let editedIndexPath = editedIndexPath {
            tableView.reloadRows(at: [editedIndexPath], with: .automatic)
            self.editedIndexPath = nil
        }
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "Edit Sting", let stingVC = segue.destination as? StingViewController {
            if let indexPath = tableView.indexPathForSelectedRow {
                editedIndexPath = indexPath
                stingVC.stingIndex = indexPath.row
            }
        }
    }
    
    func loadTrack() {
        // present music picker to load a track from ipod
        let mediaPicker = MPMediaPickerController(mediaTypes: .music)
        mediaPicker.delegate = self
        mediaPicker.showsCloudItems = false  // hides iTunes in the Cloud items, which crash the app if picked
        mediaPicker.showsItemsWithProtectedAssets = false  // hides Apple Music items, which are DRM protected
        mediaPicker.allowsPickingMultipleItems = false
        present(mediaPicker, animated: true)
    }
    
    func loadTrackFromFile() {
        // present file picker to load a track from
        let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypeAudio as String], in: .open)
        documentPicker.delegate = self
        present(documentPicker, animated: true)
    }
    
    @IBAction func edit() {
        tableView.setEditing(!tableView.isEditing, animated: true)
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch section {
        case 0:
            return "File"
        case 1:
            return "Stings"
        default:
            return nil
        }
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch section {
        case 0:
            return 1
        case 1:
            return engine.show.stings.count + 1
        default:
            return 0
        }
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch indexPath.section {
        case 0:
            return tableView.dequeueReusableCell(withIdentifier: "File Cell") ?? UITableViewCell()
        case 1:
            if indexPath.row < engine.show.stings.count {
                let cell = tableView.dequeueReusableCell(withIdentifier: "Edit Sting Cell") ?? UITableViewCell()
                
                let sting = engine.show.stings[indexPath.row]
                cell.textLabel?.text = sting.name ?? sting.songTitle
            
                return cell
            } else {
                return tableView.dequeueReusableCell(withIdentifier: "Add Sting Cell") ?? UITableViewCell()
            }
        default:
            return UITableViewCell()
        }
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        switch indexPath.section {
        case 0:
            let alert = UIAlertController(title: "New Show?", message: "Are you sure you would like to start a new show? This will delete any unsaved changes.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { action in
                tableView.deselectRow(at: indexPath, animated: true)
            })
            alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { action in
                self.engine.newShow()   // reloads playback view controller via notification
                tableView.deselectRow(at: indexPath, animated: true)
                tableView.reloadSections(IndexSet(integer: 1), with: .automatic)
            })
            present(alert, animated: true)
        case 1:
            if indexPath.row == engine.show.stings.count {
                tableView.deselectRow(at: indexPath, animated: true)
                
                #if targetEnvironment(simulator)
                    // use a document picker as the simulator doesn't have a music library
                    loadTrackFromFile()
                #else
                    // load the track with a media picker
                    loadTrack()
                #endif
            }
        default:
            return
        }
    }
    
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        guard indexPath.section == 1 else { return false }
        return indexPath.row < engine.show.stings.count  // ignores add sting button
    }
    
    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        guard indexPath.section == 1 else { return false }
        return indexPath.row < engine.show.stings.count  // ignores add sting button
    }
    <commit_msg>Update the simulator behaviour to pick a random track from its document directory instead of showing the file picker to bypass iOS 13 simulator bug.<commit_after>import UIKit
import MediaPlayer
import MobileCoreServices

class ShowViewController: UITableViewController {
    
    private let engine = Engine.shared
    private var editedIndexPath: IndexPath?
    
    @IBOutlet weak var editBarButtonItem: UIBarButtonItem!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.rightBarButtonItem = editButtonItem
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        if let editedIndexPath = editedIndexPath {
            tableView.reloadRows(at: [editedIndexPath], with: .automatic)
            self.editedIndexPath = nil
        }
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "Edit Sting", let stingVC = segue.destination as? StingViewController {
            if let indexPath = tableView.indexPathForSelectedRow {
                editedIndexPath = indexPath
                stingVC.stingIndex = indexPath.row
            }
        }
    }
    
    func loadTrack() {
        // present music picker to load a track from ipod
        let mediaPicker = MPMediaPickerController(mediaTypes: .music)
        mediaPicker.delegate = self
        mediaPicker.showsCloudItems = false  // hides iTunes in the Cloud items, which crash the app if picked
        mediaPicker.showsItemsWithProtectedAssets = false  // hides Apple Music items, which are DRM protected
        mediaPicker.allowsPickingMultipleItems = false
        present(mediaPicker, animated: true)
    }
    
    func loadTrackFromFile() {
        // present file picker to load a track from
        let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypeAudio as String], in: .open)
        documentPicker.delegate = self
        present(documentPicker, animated: true)
    }
    
    #if targetEnvironment(simulator)
    func loadRandomTrackFromDocuments() {
        guard
            let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first,
            let documents = try? FileManager.default.contentsOfDirectory(atPath: documentsURL.path)
        else { return }
        
        let audioFiles = documents.filter { $0.hasSuffix(".mp3") || $0.hasSuffix(".m4a") }
        guard audioFiles.count > 0 else { fatalError() }
        let file = audioFiles[Int.random(in: 0..<audioFiles.count)]
        let url = documentsURL.appendingPathComponent(file)
        
        if let sting = Sting(url: url) {
            engine.add(sting)
            tableView.insertRows(at: [IndexPath(row: engine.show.stings.count - 1, section: 1)], with: .automatic)
        }
    }
    #endif
    
    @IBAction func edit() {
        tableView.setEditing(!tableView.isEditing, animated: true)
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch section {
        case 0:
            return "File"
        case 1:
            return "Stings"
        default:
            return nil
        }
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch section {
        case 0:
            return 1
        case 1:
            return engine.show.stings.count + 1
        default:
            return 0
        }
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch indexPath.section {
        case 0:
            return tableView.dequeueReusableCell(withIdentifier: "File Cell") ?? UITableViewCell()
        case 1:
            if indexPath.row < engine.show.stings.count {
                let cell = tableView.dequeueReusableCell(withIdentifier: "Edit Sting Cell") ?? UITableViewCell()
                
                let sting = engine.show.stings[indexPath.row]
                cell.textLabel?.text = sting.name ?? sting.songTitle
            
                return cell
            } else {
                return tableView.dequeueReusableCell(withIdentifier: "Add Sting Cell") ?? UITableViewCell()
            }
        default:
            return UITableViewCell()
        }
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        switch indexPath.section {
        case 0:
            let alert = UIAlertController(title: "New Show?", message: "Are you sure you would like to start a new show? This will delete any unsaved changes.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { action in
                tableView.deselectRow(at: indexPath, animated: true)
            })
            alert.addAction(UIAlertAction(title: "Yes", style: .destructive) { action in
                self.engine.newShow()   // reloads playback view controller via notification
                tableView.deselectRow(at: indexPath, animated: true)
                tableView.reloadSections(IndexSet(integer: 1), with: .automatic)
            })
            present(alert, animated: true)
        case 1:
            if indexPath.row == engine.show.stings.count {
                tableView.deselectRow(at: indexPath, animated: true)
                
                #if targetEnvironment(simulator)
                    // pick a random file from the documents directory until iOS 13 syncs iCloud drive
                    loadRandomTrackFromDocuments()
                #else
                    // load the track with a media picker
                    loadTrack()
                #endif
            }
        default:
            return
        }
    }
    
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        guard indexPath.section == 1 else { return false }
        return indexPath.row < engine.show.stings.count  // ignores add sting button
    }
    
    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        guard indexPath.section == 1 else { return false }
        return indexPath.row < engine.show.stings.count  // ignores add sting button
    }
    
{'fraction_non_alphanumeric': 0.07586438402148372, 'fraction_numerical': 0.003524672708962739, 'mean_word_length': 2.068228630278064, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6635702', 'n_tokens_mistral': 3216, 'n_tokens_neox': 3014, 'n_words': 866}