 // MARK: - Entity
 
 struct Entity {
-    var tag: String
-    var range: Range<Int>
-    fileprivate var attributes: [String: AnyObject]?
-}
 
-extension Entity {
+    // MARK: - Properties
+
+    let tag: String
+
+    let range: Range<Int>
+
+    fileprivate let attributes: [String: Any]?
+
     var href: URL? {
         if tag == "a" {
             return (attributes?["href"] as? String).flatMap({ URL(string: $0) })

// MARK: - EntityEncoder

struct EntityEncoder: EncoderType {
    static func encode(_ value: Entity) -> Any {
        var dictionary = [String: Any]()

        dictionary["html_tag"] = value.tag as AnyObject?
        dictionary["position"] = [value.range.lowerBound, value.range.upperBound]
        dictionary["attributes"] = value.attributes as AnyObject?

        return dictionary as AnyObject
    }
}

    }
}

extension Entity: Equatable {
    static func == (lhs: Entity, rhs: Entity) -> Bool {
        return lhs.tag == rhs.tag
            && lhs.range == rhs.range
            && lhs.href == rhs.href
    }
}


// MARK: - EntityDecoder

struct EntityDecoder: DecoderType {
    static func decode(_ json: JSON) -> Entity? {
        guard
            let tag = json["html_tag"]?.stringValue,
            let range = json["position"]?.decode(PositionDecoder.self)
        else {
            return nil
        }

        let attributes = json["attributes"]?.dictionaryValue

        return Entity(tag: tag, range: range, attributes: attributes)
    }
}

