 
 	static func parseAttachment(_ attachmentObject: JSONDictionary) -> ParsedAttachment? {
 
-		guard let url = attachmentObject["url"] as? String else {
-			return nil
-		}
-		guard let mimeType = attachmentObject["mime_type"] as? String else {
-			return nil
-		}
-
-		let title = attachmentObject["title"] as? String
-		let sizeInBytes = attachmentObject["size_in_bytes"] as? Int
-		let durationInSeconds = attachmentObject["duration_in_seconds"] as? Int
+		guard let url = attachmentObject[Key.url] as? String else {
+			return nil
+		}
+		guard let mimeType = attachmentObject[Key.mimeType] as? String else {
+			return nil
+		}
+
+		let title = attachmentObject[Key.title] as? String
+		let sizeInBytes = attachmentObject[Key.sizeInBytes] as? Int
+		let durationInSeconds = attachmentObject[Key.durationInSeconds] as? Int
 
 		return ParsedAttachment(url: url, mimeType: mimeType, title: title, sizeInBytes: sizeInBytes, durationInSeconds: durationInSeconds)
 	}


public struct JSONFeedParser {

	public static func parse(_ parserData: ParserData) throws -> ParsedFeed? {

		do {
			guard let parsedObject = try JSONSerialization.jsonObject(with: parserData.data) as? JSONDictionary else {
				throw FeedParserError(.invalidJSON)
			}

			guard let version = parsedObject["version"] as? String, version.hasPrefix("https://jsonfeed.org/version/") else {
				throw FeedParserError(.jsonFeedVersionNotFound)
			}
			guard let itemsArray = parsedObject["items"] as? JSONArray else {
				throw FeedParserError(.jsonFeedItemsNotFound)
			}
			guard let title = parsedObject["title"] as? String else {
				throw FeedParserError(.jsonFeedTitleNotFound)
			}

			let authors = parseAuthors(parsedObject)
			let homePageURL = parsedObject["home_page_url"] as? String
			let feedURL = parsedObject["feed_url"] as? String ?? parserData.url
			let feedDescription = parsedObject["description"] as? String
			let nextURL = parsedObject["next_url"] as? String
			let iconURL = parsedObject["icon"] as? String
			let faviconURL = parsedObject["favicon"] as? String
			let expired = parsedObject["expired"] as? Bool ?? false
			let hubs = parseHubs(parsedObject)

			let items = parseItems(itemsArray, parserData.url)

			return ParsedFeed(type: .jsonFeed, title: title, homePageURL: homePageURL, feedURL: feedURL, feedDescription: feedDescription, nextURL: nextURL, iconURL: iconURL, faviconURL: faviconURL, authors: authors, expired: expired, hubs: hubs, items: items)

		}
		catch { throw error }
	}
}


			return nil
		}

		let contentHTML = itemDictionary[Key.contentHTML] as? String
		let contentText = itemDictionary[Key.contentText] as? String
		if contentHTML == nil && contentText == nil {
			return nil
		}
		let decodedContentHTML = contentHTML?.rsparser_stringByDecodingHTMLEntities()

		let url = itemDictionary[Key.url] as? String
		let externalURL = itemDictionary[Key.externalURL] as? String
		let title = itemDictionary[Key.title] as? String
		let summary = itemDictionary[Key.summary] as? String
		let imageURL = itemDictionary[Key.image] as? String
		let bannerImageURL = itemDictionary[Key.bannerImage] as? String

		let datePublished = parseDate(itemDictionary[Key.datePublished] as? String)
		let dateModified = parseDate(itemDictionary[Key.dateModified] as? String)

		let authors = parseAuthors(itemDictionary)
		var tags: Set<String>? = nil
		if let tagsArray = itemDictionary[Key.tags] as? [String] {
			tags = Set(tagsArray)
		}
		let attachments = parseAttachments(itemDictionary)
