 
   }
   
-}
-
-extension Model: DeinitObservable { }+}

  private var registeredBubbles = Set<String>()
  
  public final func registerFor<T where T: BubbleNotificationName>(name: T) {
    registeredBubbles.insert(T.domain + "." + name.rawValue)
  }
  
  public final func unregisterFrom<T where T: BubbleNotificationName>(name: T) {
    registeredBubbles.remove(T.domain + "." + name.rawValue)
  }
  
  public final func isRegisteredFor<T where T: BubbleNotificationName>(name: T) -> Bool {
    return registeredBubbles.contains(T.domain + "." + name.rawValue)
  }
  
  public func raise<T where T: BubbleNotificationName>(name: T, withObject object: Any? = nil, sender: Model) {
    if isRegisteredFor(name) {
      handle(BubbleNotification(name: name, object: object), sender: sender)
    } else {
      parent?.raise(name, withObject: object, sender: sender)
    }
  }
  
  public func handle(bubble: BubbleNotification, sender: Model) {}
  
  //Errors
  
  //TODO: extensions
  private var registeredErrors = [String: Set<Int>]()
  
  public final func registerFor<T where T: ErrorCode>(code: T) {
    var allCodes = registeredErrors[T.domain] ?? []
    allCodes.insert(code.rawValue)
    registeredErrors[T.domain] = allCodes
  }
  
  public final func registerForErrorCodes<T where T: ErrorCode>(codes: [T]) {
    var allCodes = registeredErrors[T.domain] ?? []
    let mappedCodes = codes.map { $0.rawValue }
    mappedCodes.forEach { allCodes.insert($0) }
    registeredErrors[T.domain] = allCodes
  }
  
  public final func unregisterFrom<T where T: ErrorCode>(code code: T) {
    if let codes = registeredErrors[T.domain] {
      var filteredCodes = codes
      filteredCodes.remove(code.rawValue)
      registeredErrors[T.domain] = filteredCodes
    }
  }
  


import Foundation

extension Model: DeinitObservable { }

public class Model {
  
  public private(set) weak var parent: Model!
