<commit_before>import Foundation
import DotEnv
import Dispatch
import Yaml

public struct NewWorkshopManager {
  public enum Error: Swift.Error {
    case updateFailed(String)
  }

  private static let directoryName = "workshops"

  /// A concurrent queue used for parallelising workshop data updates
  private static var updateQueue = DispatchQueue(
    label: "com.hac.website.workshops-update-queue",
    qos: .background,
    attributes: .concurrent
  )

  private static var pollSource: DispatchSourceTimer! = nil
  private static var currentlyUpdating = false

  /// The list of Workshops as derived from the workshop repos last time they were processed. Keys are workshop repo names
  public private(set) static var workshops: [String: NewWorkshop] = [:]

  /// All the workshop repos that we know about. Keys are workshop repo names
  private static var workshopRepoUtils: [String: GitUtil] = [:]

  public static func update() {
    print("Updating workshops...")
    // Prevent multiple updates at once (might happen if an update takes longer than the poll interval)
    if !currentlyUpdating {
      currentlyUpdating = true
      updateRepoList()
      updateWorkshopsData()
      currentlyUpdating = false
    }
    print("Workshops updated")
  }

  public static func startPoll() {
    let pollQueue = DispatchQueue(label: "com.hac.website.workshops-poll-timer", attributes: .concurrent)
    pollSource?.cancel()
    pollSource = DispatchSource.makeTimerSource(queue: pollQueue)
    pollSource?.setEventHandler {
      update()
    }
    pollSource?.schedule(
      deadline: DispatchTime.now(),
      repeating: .seconds(600),
      leeway: .seconds(2)
    )
    pollSource?.resume()
  }<commit_msg>Avoid unnecessary optional unwraps<commit_after>import Foundation
import DotEnv
import Dispatch
import Yaml

public struct NewWorkshopManager {
  public enum Error: Swift.Error {
    case updateFailed(String)
  }

  private static let directoryName = "workshops"

  /// A concurrent queue used for parallelising workshop data updates
  private static var updateQueue = DispatchQueue(
    label: "com.hac.website.workshops-update-queue",
    qos: .background,
    attributes: .concurrent
  )

  private static var pollSource: DispatchSourceTimer! = nil
  private static var currentlyUpdating = false

  /// The list of Workshops as derived from the workshop repos last time they were processed. Keys are workshop repo names
  public private(set) static var workshops: [String: NewWorkshop] = [:]

  /// All the workshop repos that we know about. Keys are workshop repo names
  private static var workshopRepoUtils: [String: GitUtil] = [:]

  public static func update() {
    print("Updating workshops...")
    // Prevent multiple updates at once (might happen if an update takes longer than the poll interval)
    if !currentlyUpdating {
      currentlyUpdating = true
      updateRepoList()
      updateWorkshopsData()
      currentlyUpdating = false
    }
    print("Workshops updated")
  }

  public static func startPoll() {
    let pollQueue = DispatchQueue(label: "com.hac.website.workshops-poll-timer", attributes: .concurrent)
    pollSource?.cancel()
    pollSource = DispatchSource.makeTimerSource(queue: pollQueue)
    pollSource.setEventHandler {
      update()
    }
    pollSource.schedule(
      deadline: DispatchTime.now(),
      repeating: .seconds(10),
      leeway: .seconds(2)
    )
    pollSource.resume()
  }
{'fraction_non_alphanumeric': 0.08388969521044992, 'fraction_numerical': 0.0020319303338171262, 'mean_word_length': 3.546174142480211, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5927821', 'n_tokens_mistral': 954, 'n_tokens_neox': 919, 'n_words': 313}