 
 public struct JSONFeedParser {
 
+	struct Key {
+		static let version = "version"
+		static let items = "items"
+		static let title = "title"
+		static let homePageURL = "home_page_url"
+		static let feedURL = "feed_url"
+		static let feedDescription = "description"
+		static let nextURL = "next_url"
+		static let icon = "icon"
+		static let favicon = "favicon"
+		static let expired = "expired"
+		static let author = "author"
+		static let name = "name"
+		static let url = "url"
+		static let avatar = "avatar"
+		static let hubs = "hubs"
+		static let type = "type"
+		static let contentHTML = "content_html"
+		static let contentText = "content_text"
+		static let externalURL = "external_url"
+		static let summary = "summary"
+		static let image = "image"
+		static let bannerImage = "banner_image"
+		static let datePublished = "date_published"
+		static let dateModified = "date_modified"
+		static let tags = "tags"
+		static let uniqueID = "id"
+		static let attachments = "attachments"
+		static let mimeType = "mime_type"
+		static let sizeInBytes = "size_in_bytes"
+		static let durationInSeconds = "duration_in_seconds"
+	}
+
+	static let jsonFeedVersionPrefix = "https://jsonfeed.org/version/"
+
 	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 }
+		guard let d = JSONUtilities.dictionary(with: parserData.data) else {
+			throw FeedParserError(.invalidJSON)
+		}
+
+		guard let version = d[Key.version] as? String, version.hasPrefix(JSONFeedParser.jsonFeedVersionPrefix) else {
+			throw FeedParserError(.jsonFeedVersionNotFound)
+		}
+		guard let itemsArray = d[Key.items] as? JSONArray else {
+			throw FeedParserError(.jsonFeedItemsNotFound)
+		}
+		guard let title = d[Key.title] as? String else {
+			throw FeedParserError(.jsonFeedTitleNotFound)
+		}
+
+		let authors = parseAuthors(d)
+		let homePageURL = d[Key.homePageURL] as? String
+		let feedURL = d[Key.feedURL] as? String ?? parserData.url
+		let feedDescription = d[Key.feedDescription] as? String
+		let nextURL = d[Key.nextURL] as? String
+		let iconURL = d[Key.icon] as? String
+		let faviconURL = d[Key.favicon] as? String
+		let expired = d[Key.expired] as? Bool ?? false
+		let hubs = parseHubs(d)
+
+		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)
 	}
 }
 

			return nil
		}

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

		let url = itemDictionary["url"] as? String
		let externalURL = itemDictionary["external_url"] as? String
		let title = itemDictionary["title"] as? String
		let summary = itemDictionary["summary"] as? String
		let imageURL = itemDictionary["image"] as? String
		let bannerImageURL = itemDictionary["banner_image"] as? String

		let datePublished = parseDate(itemDictionary["date_published"] as? String)
		let dateModified = parseDate(itemDictionary["date_modified"] as? String)

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


	static func parseAttachments(_ itemDictionary: JSONDictionary) -> Set<ParsedAttachment>? {

		guard let attachmentsArray = itemDictionary[Key.attachments] as? JSONArray else {
			return nil
		}
		return Set(attachmentsArray.flatMap { parseAttachment($0) })
