<commit_before>class AuthenticatorList
  KEYCHAIN_SERVICE = 'bna_authenticators'
  USERDEFAULTS_KEY = 'bna_authenticator_serials'

  class << self
    def number_of_authenticators
      authenticator_serials.count
    end

    def authenticator_at_index(index)
      serial = authenticator_serials[index]
      secret = SSKeychain.passwordForService(KEYCHAIN_SERVICE, account: serial)
      Bnet::Authenticator.new(serial, secret)
    end

    def add_authenticator(authenticator)
      return false if authenticator_exists? authenticator
      keychain_add_authenticator(authenticator) && userdefaults_add_authenticator(authenticator)
    end

    def del_authenticator(authenticator)
      keychain_del_authenticator(authenticator) && userdefaults_del_authenticator(authenticator)
    end

    def move_authenticator_at(from, to: to)
      userdefaults_move_authenticator_at(from, to: to)
    end

    def authenticator_exists?(authenticator)
      serial = authenticator.is_a?(Bnet::Authenticator) ? authenticator.serial : Bnet::Attributes::Serial.new(authenticator).to_s
      !!SSKeychain.passwordForService(KEYCHAIN_SERVICE, account: serial)
    end

    private

    def authenticator_serials
      userdefaults_authenticator_serials || keychain_authenticator_serials
    end

    def keychain_add_authenticator(authenticator)
      SSKeychain.setPassword(authenticator.secret,
                             forService: KEYCHAIN_SERVICE,
                             account: authenticator.serial)
    end

    def keychain_del_authenticator(authenticator)
      SSKeychain.deletePasswordForService(KEYCHAIN_SERVICE,
                                          account: authenticator.serial)
    end

    def keychain_authenticator_serials
      SSKeychain.accountsForService(KEYCHAIN_SERVICE).to_a.map do |v|
        v[KSecAttrAccount]
      end
    end

    def userdefaults_move_authenticator_at(from, to: to)
      serials = authenticator_serials.dup
      serials.insert(to, serials.delete_at(from))
      NSUserDefaults.standardUserDefaults.setObject(serials, forKey: USERDEFAULTS_KEY)
    end

    def userdefaults_add_authenticator(authenticator)
      serials = authenticator_serials.dup << authenticator.serial
      NSUserDefaults.standardUserDefaults.setObject(serials, forKey: USERDEFAULTS_KEY)
    end

    def userdefaults_del_authenticator(authenticator)
      serials = authenticator_serials.dup
      serials.delete authenticator.serial
      NSUserDefaults.standardUserDefaults.setObject(serials, forKey: USERDEFAULTS_KEY)
    end

    def userdefaults_authenticator_serials
      NSUserDefaults.standardUserDefaults.objectForKey(USERDEFAULTS_KEY)
    end

    def userdefaults_save(serials)
    end
  end
end<commit_msg>recover from data inconsistency (might be caused by NSUserDefaults saving failure)<commit_after>class AuthenticatorList
  KEYCHAIN_SERVICE = 'bna_authenticators'
  USERDEFAULTS_KEY = 'bna_authenticator_serials'

  class << self
    def number_of_authenticators
      authenticator_serials.count
    end

    def authenticator_at_index(index)
      serial = authenticator_serials[index]
      secret = SSKeychain.passwordForService(KEYCHAIN_SERVICE, account: serial)
      Bnet::Authenticator.new(serial, secret)
    end

    def add_authenticator(authenticator)
      return false if authenticator_exists? authenticator
      keychain_add_authenticator(authenticator) && userdefaults_add_authenticator(authenticator)
    end

    def del_authenticator(authenticator)
      keychain_del_authenticator(authenticator) && userdefaults_del_authenticator(authenticator)
    end

    def move_authenticator_at(from, to: to)
      userdefaults_move_authenticator_at(from, to: to)
    end

    def authenticator_exists?(authenticator)
      serial = authenticator.is_a?(Bnet::Authenticator) ? authenticator.serial : Bnet::Attributes::Serial.new(authenticator).to_s
      !!SSKeychain.passwordForService(KEYCHAIN_SERVICE, account: serial)
    end

    private

    def authenticator_serials
      a = userdefaults_authenticator_serials.to_a
      b = keychain_authenticator_serials
      a - (a - b) + (b - a)
    end

    def keychain_add_authenticator(authenticator)
      SSKeychain.setPassword(authenticator.secret,
                             forService: KEYCHAIN_SERVICE,
                             account: authenticator.serial)
    end

    def keychain_del_authenticator(authenticator)
      SSKeychain.deletePasswordForService(KEYCHAIN_SERVICE,
                                          account: authenticator.serial)
    end

    def keychain_authenticator_serials
      SSKeychain.accountsForService(KEYCHAIN_SERVICE).to_a.map do |v|
        v[KSecAttrAccount]
      end
    end

    def userdefaults_move_authenticator_at(from, to: to)
      serials = authenticator_serials.dup
      serials.insert(to, serials.delete_at(from))
      userdefaults_save(serials)
    end

    def userdefaults_add_authenticator(authenticator)
      serials = authenticator_serials.dup
      serials << authenticator.serial unless serials.last == authenticator.serial
      userdefaults_save(serials)
    end

    def userdefaults_del_authenticator(authenticator)
      serials = authenticator_serials.dup
      serials.delete authenticator.serial
      userdefaults_save(serials)
    end

    def userdefaults_authenticator_serials
      NSUserDefaults.standardUserDefaults.objectForKey(USERDEFAULTS_KEY)
    end

    def userdefaults_save(serials)
      NSUserDefaults.standardUserDefaults.setObject(serials, forKey: USERDEFAULTS_KEY)
    end
  end
end
{'fraction_non_alphanumeric': 0.059634670487106016, 'fraction_numerical': 0.0, 'mean_word_length': 3.6893366918555834, 'pattern_counts': {'":': 0, '<': 11, '<?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': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1985317', 'n_tokens_mistral': 1694, 'n_tokens_neox': 1600, 'n_words': 265}