diff --git a/Gemfile b/Gemfile index 3ea2fefaec..7c4250d7d2 100644 --- a/Gemfile +++ b/Gemfile @@ -30,7 +30,6 @@ gem 'csv' gem 'daemons' gem 'delayed_job_active_record' gem 'docsplit', git: 'https://github.com/documentcloud/docsplit.git' -gem 'doi_query_tool', git: 'https://github.com/seek4science/DOI-query-tool.git' gem 'doorkeeper' gem 'dotenv-rails' gem 'equivalent-xml' diff --git a/Gemfile.lock b/Gemfile.lock index a2631ff04d..47e1222297 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,13 +16,6 @@ GIT specs: docsplit (0.7.6) -GIT - remote: https://github.com/seek4science/DOI-query-tool.git - revision: 7c2ba934885ad404d964cd371e236d3348efb63c - specs: - doi_query_tool (1.0.1) - libxml-ruby (>= 2.6.0) - GIT remote: https://github.com/seek4science/zenodo-client.git revision: 72c19d105ec2aab5298bf6c5bd50d30c798f169e @@ -1076,7 +1069,6 @@ DEPENDENCIES database_cleaner delayed_job_active_record docsplit! - doi_query_tool! doorkeeper dotenv-rails equivalent-xml diff --git a/app/helpers/publications_helper.rb b/app/helpers/publications_helper.rb index c0b9e930fa..54930497af 100644 --- a/app/helpers/publications_helper.rb +++ b/app/helpers/publications_helper.rb @@ -1,5 +1,3 @@ -require 'doi/record' - module PublicationsHelper def author_to_person_options(selected_id, suggestion) projects = Project.includes(:people) @@ -14,13 +12,14 @@ def author_to_person_options(selected_id, suggestion) end def publication_registered_mode(mode) - if mode == Publication::REGISTRATION_BY_PUBMED + case mode + when Publication::REGISTRATION_BY_PUBMED 'by PubMed ID' - elsif mode == Publication::REGISTRATION_BY_DOI + when Publication::REGISTRATION_BY_DOI 'by DOI' - elsif mode == Publication::REGISTRATION_MANUALLY + when Publication::REGISTRATION_MANUALLY 'manually' - elsif mode == Publication::REGISTRATION_FROM_BIBTEX + when Publication::REGISTRATION_FROM_BIBTEX 'imported from a bibtex file' else `unknown` diff --git a/app/models/publication.rb b/app/models/publication.rb index 9a19d8a153..54aeb985a0 100755 --- a/app/models/publication.rb +++ b/app/models/publication.rb @@ -1,4 +1,5 @@ require 'libxml' +require 'seek/doi/base_exception' class Publication < ApplicationRecord include Seek::Rdf::RdfGeneration @@ -48,7 +49,7 @@ class Publication < ApplicationRecord has_one :content_blob, ->(r) { where('content_blobs.asset_version =? AND deleted=?', r.version, false) }, as: :asset, foreign_key: :asset_id explicit_versioning(:version_column => "version", sync_ignore_columns: ['license','other_creators']) do - acts_as_versioned_resource + acts_as_versioned_resource has_one :content_blob, -> (r) { where('content_blobs.asset_version =? AND content_blobs.asset_type =?', r.version, r.parent.class.name) }, :primary_key => :publication_id,:foreign_key => :asset_id @@ -188,11 +189,11 @@ def extract_metadata(pubmed_id, doi) end if reference.respond_to?(:pubmed) - result = extract_pubmed_metadata(reference) + extract_pubmed_metadata(reference) else - result = extract_doi_metadata(reference) + extract_doi_metadata(reference) end - + reference.authors.each_with_index do |author, index| publication_authors.build(first_name: author.first_name, last_name: author.last_name, @@ -230,7 +231,7 @@ def extract_doi_metadata(doi_record) self.citation = doi_record.citation self.publisher = doi_record.publisher self.booktitle = doi_record.booktitle - self.editor = doi_record.editors.map(&:name).join(" and ") + self.editor = doi_record.editors end # @param bibtex_record BibTeX entity from bibtex-ruby gem @@ -239,7 +240,7 @@ def extract_bibtex_metadata(bibtex_record) self.publication_type_id = PublicationType.get_publication_type_id(bibtex_record) self.title = bibtex_record[:title].try(:to_s).gsub /{|}/, '' unless bibtex_record[:title].nil? self.title = bibtex_record[:chapter].try(:to_s).gsub /{|}/, '' if (self.title.nil? && !bibtex_record[:chapter].nil?) - self.title += ( ":"+ (bibtex_record[:subtitle].try(:to_s).gsub /{|}/, '')) unless bibtex_record[:subtitle].nil? + self.title += ( ":#{(bibtex_record[:subtitle].try(:to_s).gsub /{|}/, '')}") unless bibtex_record[:subtitle].nil? if check_bibtex_file (bibtex_record) self.abstract = bibtex_record[:abstract].try(:to_s) @@ -345,31 +346,31 @@ def generate_citation(bibtex_record) if publication_type.is_journal? self.citation += self.journal.nil? ? '':self.journal - self.citation += volume.blank? ? '': ' '+volume - self.citation += number.nil? ? '' : '('+ number+')' - self.citation += pages.blank? ? '' : (':'+pages) + self.citation += volume.blank? ? '': " #{volume}" + self.citation += number.nil? ? '' : "(#{number})" + self.citation += pages.blank? ? '' : (":#{pages}") =begin unless year.nil? self.citation += year.nil? ? '' : (' '+year) end =end elsif publication_type.is_booklet? - self.citation += howpublished.blank? ? '': ''+ howpublished - self.citation += address.nil? ? '' : (', '+ address) + self.citation += howpublished.blank? ? '': "#{howpublished}" + self.citation += address.nil? ? '' : (", #{address}") =begin unless year.nil? self.citation += year.nil? ? '' : (' '+year) end =end elsif publication_type.is_inbook? - self.citation += self.booktitle.nil? ? '' : ('In '+ self.booktitle) - self.citation += volume.blank? ? '' : (', volume '+ volume) - self.citation += series.blank? ? '' : (' of '+series) - self.citation += pages.blank? ? '' : (', '+ page_or_pages + ' '+pages) - self.citation += self.editor.blank? ? '' : (', Eds: '+ self.editor) - self.citation += self.publisher.blank? ? '' : (', '+ self.publisher) + self.citation += self.booktitle.nil? ? '' : ("In #{self.booktitle}") + self.citation += volume.blank? ? '' : (", volume #{volume}") + self.citation += series.blank? ? '' : (" of #{series}") + self.citation += pages.blank? ? '' : (", #{page_or_pages} #{pages}") + self.citation += self.editor.blank? ? '' : (", Eds: #{self.editor}") + self.citation += self.publisher.blank? ? '' : (", #{self.publisher}") unless address.nil? || (self.booktitle.try(:include?, address)) - self.citation += address.nil? ? '' : (', '+ address) + self.citation += address.nil? ? '' : (", #{address}") end =begin unless self.booktitle.try(:include?, year) @@ -380,14 +381,14 @@ def generate_citation(bibtex_record) =end elsif publication_type.is_inproceedings? || publication_type.is_incollection? || publication_type.is_book? # InProceedings / InCollection - self.citation += self.booktitle.nil? ? '' : ('In '+ self.booktitle) - self.citation += volume.blank? ? '' : (', vol. '+ volume) - self.citation += series.blank? ? '' : (' of '+series) - self.citation += pages.blank? ? '' : (', '+ page_or_pages + ' '+pages) - self.citation += self.editor.blank? ? '' : (', Eds: '+ self.editor) - self.citation += self.publisher.blank? ? '' : (', '+ self.publisher) + self.citation += self.booktitle.nil? ? '' : ("In #{self.booktitle}") + self.citation += volume.blank? ? '' : (", vol. #{volume}") + self.citation += series.blank? ? '' : (" of #{series}") + self.citation += pages.blank? ? '' : (", #{page_or_pages} #{pages}") + self.citation += self.editor.blank? ? '' : (", Eds: #{self.editor}") + self.citation += self.publisher.blank? ? '' : (", #{self.publisher}") unless address.nil? || (self.booktitle.try(:include?, address)) - self.citation += address.nil? ? '' : (', '+ address) + self.citation += address.nil? ? '' : (", #{address}") end =begin unless self.booktitle.try(:include?, year) @@ -398,19 +399,19 @@ def generate_citation(bibtex_record) =end elsif publication_type.is_phd_thesis? || publication_type.is_masters_thesis? || publication_type.is_bachelor_thesis? #PhD/Master Thesis - self.citation += school.nil? ? '' : (' '+ school) + self.citation += school.nil? ? '' : (" #{school}") self.errors.add(:base,'A thesis need to have a school') if school.nil? - self.citation += year.nil? ? '' : (', '+ year) - self.citation += tutor.nil? ? '' : (', '+ tutor+'(Tutor)') - self.citation += tutorhits.nil? ? '' : (', '+ tutorhits+'(HITS Tutor)') - self.citation += url.nil? ? '' : (', '+ url) + self.citation += year.nil? ? '' : (", #{year}") + self.citation += tutor.nil? ? '' : (", #{tutor}(Tutor)") + self.citation += tutorhits.nil? ? '' : (", #{tutorhits}(HITS Tutor)") + self.citation += url.nil? ? '' : (", #{url}") elsif publication_type.is_proceedings? # Proceedings are conference proceedings, it has no authors but editors # Book self.journal = self.title - self.citation += volume.blank? ? '' : ('vol. '+ volume) - self.citation += series.blank? ? '' : (' of '+series) - self.citation += self.publisher.blank? ? '' : (', '+ self.publisher) + self.citation += volume.blank? ? '' : ("vol. #{volume}") + self.citation += series.blank? ? '' : (" of #{series}") + self.citation += self.publisher.blank? ? '' : (", #{self.publisher}") =begin unless month.nil? && year.nil? self.citation += self.citation.blank? ? '' : ',' @@ -420,20 +421,20 @@ def generate_citation(bibtex_record) =end elsif publication_type.is_tech_report? self.citation += institution.blank? ? ' ': institution - self.citation += type.blank? ? ' ' : (', '+type) + self.citation += type.blank? ? ' ' : (", #{type}") elsif publication_type.is_unpublished? self.citation += note.blank? ? ' ': note end if self.doi.blank? && self.citation.blank? self.citation += archivePrefix unless archivePrefix.nil? - self.citation += (self.citation.blank? ? primaryClass : (','+primaryClass)) unless primaryClass.nil? - self.citation += (self.citation.blank? ? eprint : (','+eprint)) unless eprint.nil? + self.citation += (self.citation.blank? ? primaryClass : (",#{primaryClass}")) unless primaryClass.nil? + self.citation += (self.citation.blank? ? eprint : (",#{eprint}")) unless eprint.nil? self.journal = self.citation if self.journal.blank? end if self.doi.blank? && self.citation.blank? - self.citation += url.blank? ? '': url + self.citation += url.blank? ? '': url end self.citation = self.citation.try(:to_s).strip.gsub(/^,/,'').strip end @@ -453,20 +454,24 @@ def fetch_pubmed_or_doi_result(pubmed_id, doi) end elsif !doi.blank? begin - query = DOI::Query.new(Seek::Config.crossref_api_email) - result = query.fetch(doi) + + result = Seek::Doi::Parser.parse(doi) @error = 'Unable to get result' if result.blank? @error = 'Unable to get DOI' if result.title.blank? - rescue DOI::MalformedDOIException - @error = 'The DOI you entered appears to be malformed.' - rescue DOI::NotFoundException - @error = 'The DOI you entered could not be resolved.' - rescue DOI::RecordNotSupported + rescue Seek::Doi::RANotSupported => e + @error = "#{e.message} Please enter the publication in another way." + rescue Seek::Doi::FetchException => e + @error = e.message + rescue Seek::Doi::MalformedDOIException => e + @error = e.message + rescue Seek::Doi::NotFoundException => e + @error = e.message + rescue Seek::Doi::RecordNotSupported @error = 'The DOI resolved to an unsupported resource type.' - rescue RuntimeError => exception - @error = 'There was a problem contacting the DOI query service. Please try again later' - Seek::Errors::ExceptionForwarder.send_notification(exception, data: {message: "Problem accessing crossref using DOI #{doi}"}) + rescue RuntimeError => e + @error = 'There was a problem contacting the DOI query service. Please add the publication manually instead.' + Seek::Errors::ExceptionForwarder.send_notification(exception, data: {message: "Problem fetching DOI #{doi} : #{e.message}"}) end else @error = 'Please enter either a DOI or a PubMed ID for the publication.' @@ -620,7 +625,7 @@ def check_bibtex_file (bibtex_record) end if (%w[InCollection InProceedings].include? self.publication_type.title) && (bibtex_record[:booktitle].blank?) - errors.add(:base, "An #{self.publication_type.title} needs to have a booktitle.") + errors.add(:base, "An #{self.publication_type.title} needs to have a booktitle.") return false end diff --git a/lib/seek/doi/author.rb b/lib/seek/doi/author.rb new file mode 100644 index 0000000000..89d9ea6193 --- /dev/null +++ b/lib/seek/doi/author.rb @@ -0,0 +1,19 @@ +module Seek + module Doi + class Author + + # todo: add more fields if needed (e.g., affiliation, ORCID) + # e.g.{"ORCID"=>"https://orcid.org/0000-0002-5263-5070", "authenticated-orcid"=>false, "given"=>"K. Jarrod", "family"=>"Millman", "sequence"=>"additional", "affiliation"=>[]} + attr_accessor :first_name, :last_name + + def initialize(first_name:, last_name:) + @first_name = first_name + @last_name = last_name + end + + def full_name + [first_name, last_name].compact.join(' ') + end + end + end +end diff --git a/lib/seek/doi/base_exception.rb b/lib/seek/doi/base_exception.rb new file mode 100644 index 0000000000..5cae405884 --- /dev/null +++ b/lib/seek/doi/base_exception.rb @@ -0,0 +1,21 @@ +module Seek + module Doi + class BaseException < RuntimeError + def initialize(msg = 'A DOI exception occurred') + super(msg) + end + + def backtrace + cause ? cause.backtrace : super + end + end + + class UnrecognizedTypeException < BaseException; end + class FetchException < BaseException; end + class ParseException < BaseException; end + class MalformedDOIException < BaseException; end + class NotFoundException < BaseException; end + class RecordNotSupported < BaseException; end + class RANotSupported < BaseException; end + end +end diff --git a/lib/seek/doi/parser.rb b/lib/seek/doi/parser.rb new file mode 100644 index 0000000000..c60946520a --- /dev/null +++ b/lib/seek/doi/parser.rb @@ -0,0 +1,49 @@ +require 'open-uri' +require 'json' + +module Seek + module Doi + class Parser + DOI_ENDPOINT = 'https://doi.org'.freeze + + def self.parse(doi) + + agency = get_doi_ra(doi) + + case agency + when 'DataCite' + Seek::Doi::Parsers::DataciteParser.new.parse(doi) + when 'Crossref' + Seek::Doi::Parsers::CrossrefParser.new.parse(doi) + else + raise Seek::Doi::RANotSupported, "DOI registration agency '#{agency}' is not supported." + end + rescue OpenURI::HTTPError => e + # Handle RA resolution issues + raise Seek::Doi::FetchException, "Error resolving DOI #{doi}: #{e.message}" + rescue Seek::Doi::BaseException + raise # Re-raise already handled domain exceptions + rescue StandardError => e + # Fallback for truly unexpected errors + raise Seek::Doi::FetchException, "Unexpected error resolving DOI #{doi}: #{e.message}" + end + + private_class_method def self.get_doi_ra(doi) + url = "#{DOI_ENDPOINT}/ra/#{doi}" + response = URI.open(url).read + data = JSON.parse(response) + ra = data.dig(0, 'RA') + status = data.dig(0, 'status') + + case status + when 'Invalid DOI' + raise Seek::Doi::MalformedDOIException, "Invalid DOI format: #{doi}." + when 'DOI does not exist' + raise Seek::Doi::NotFoundException, "DOI does not exist: #{doi}." + end + raise Seek::Doi::NotFoundException, "No registration agency found for DOI #{doi}" if ra.blank? + ra + end + end + end +end diff --git a/lib/seek/doi/parsers/base_parser.rb b/lib/seek/doi/parsers/base_parser.rb new file mode 100644 index 0000000000..6945fc391e --- /dev/null +++ b/lib/seek/doi/parsers/base_parser.rb @@ -0,0 +1,145 @@ +require 'net/http' +require 'json' +require 'cgi' +require 'ostruct' + +module Seek + module Doi + module Parsers + class BaseParser + def parse(doi) + url = build_url(doi) + Rails.logger.info("Fetching metadata for DOI #{doi} from #{url}") + + response = perform_request(url) + data = parse_response_body(response) + + raise Seek::Doi::ParseException, "Empty metadata response for DOI #{doi}" if data.blank? + + metadata = decode_html_entities_in_hash(extract_metadata(data)) + metadata[:citation] ||= build_citation(metadata) + + build_struct(metadata) + + rescue JSON::ParserError => e + raise Seek::Doi::ParseException, "Error parsing JSON for DOI #{doi}: #{e.message}" + rescue Seek::Doi::BaseException + raise + rescue StandardError => e + raise Seek::Doi::ParseException, "Unexpected error while parsing DOI #{doi}: #{e.message}" + end + + + protected + + def normalize_metadata(raw) + { + type: raw[:type], + title: raw[:title], + authors: raw[:authors], + journal: raw[:journal], + date_published: raw[:date_published], + doi: raw[:doi], + abstract: raw[:abstract], + citation: raw[:citation], + editors: raw[:editors], + booktitle: raw[:booktitle], + publisher: raw[:publisher], + url: raw[:url], + page: raw[:page] + }.compact + end + + # Must be implemented in subclasses + def build_url(_doi) + raise NotImplementedError, "#{self.class.name} must implement #build_url" + end + + # Must be implemented in subclasses + def parse_response_body(_response) + raise NotImplementedError, "#{self.class.name} must implement #parse_response_body" + end + + def build_struct(raw) + OpenStruct.new(normalize_metadata(raw)) + end + + # optional for subclasses to override + def build_citation(_data) + default_citation(_data) + end + + + + # Generic network handler + def perform_request(uri, accept_header: 'application/json') + Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http| + request = Net::HTTP::Get.new(uri) + request['Accept'] = accept_header + response = http.request(request) + + case response.code.to_i + when 200 + response + when 204 + raise Seek::Doi::FetchException, "No metadata available for DOI #{uri}" + when 404 + raise Seek::Doi::NotFoundException, "DOI not found: #{uri}" + else + raise Seek::Doi::FetchException, "Unexpected HTTP #{response.code} #{response.message} for #{uri}" + end + end + rescue SocketError, Timeout::Error => e + raise Seek::Doi::FetchException, "Network error fetching DOI metadata: #{e.message}" + rescue URI::InvalidURIError => e + raise Seek::Doi::MalformedDOIException, "Invalid DOI or malformed URI: #{e.message}" + end + + + # HTML decoding utility + def decode_html_entities_in_hash(hash) + hash.transform_values do |value| + case value + when String + CGI.unescapeHTML(value) + when Array + value.map { |v| v.is_a?(String) ? CGI.unescapeHTML(v) : v } + when Hash + decode_html_entities_in_hash(value) + else + value + end + end + end + + # Generic helpers for author/editor parsing + def extract_authors_as_objects(list) + return [] unless list.is_a?(Array) + + list.map do |a| + if a['given'] && a['family'] + Seek::Doi::Author.new(first_name: a['given'], last_name: a['family']) + elsif a['givenName'] && a['familyName'] + Seek::Doi::Author.new(first_name: a['givenName'], last_name: a['familyName']) + elsif a['name'] + Seek::Doi::Author.new(first_name: a['name'], last_name: '') + end + end.compact + end + + def extract_editors(list) + return [] unless list.is_a?(Array) + list.map { |e| [e['given'], e['family'], e['givenName'], e['familyName']].compact.first(2).join(' ') } + end + + def default_citation(data) + parts = [] + parts << data[:publisher] if data[:publisher] + parts << data[:url] if data[:url] + parts.join('. ') + (parts.empty? ? '' : '.') + end + + end + end + end +end diff --git a/lib/seek/doi/parsers/crossref_parser.rb b/lib/seek/doi/parsers/crossref_parser.rb new file mode 100644 index 0000000000..87f4da0182 --- /dev/null +++ b/lib/seek/doi/parsers/crossref_parser.rb @@ -0,0 +1,159 @@ +module Seek + module Doi + module Parsers + class CrossrefParser < BaseParser + CROSSREF_API_ENDPOINT = 'https://api.crossref.org/works'.freeze + + private + + def build_url(doi) + URI("#{CROSSREF_API_ENDPOINT}/#{doi}") + end + + def parse_response_body(response) + json = JSON.parse(response.body) + json['message'] + end + + def extract_metadata(data) + { + type: data['type'] || 'unspecified', + title: [Array(data['title']).first, Array(data['subtitle']).first].compact.join(':'), + abstract: clean_abstract(data['abstract']), + date_published: extract_date(data)&.to_s, + journal: Array(data['container-title']).last, + short_journal_title: Array(data['short-container-title']).last, + doi: data['DOI'], + publisher: data['publisher'], + booktitle: data['container-title'].last, + editors: extract_editors(data['editor']).join(' and '), + authors: extract_authors_as_objects(data['author']), + url: data['URL'], + volume: data['volume'], + issue: data['issue'], + page: data['page'], + location: data['event']&.[]('location') || data['publisher-location'], + article_number: data['article-number'] + } + end + + def clean_abstract(abstract) + return nil if abstract.nil? + abstract.gsub(/<\/?jats:[^>]+>/, '').strip + end + + def extract_date(data) + get_date_parts = ->(key) do + if data[key] && data[key]['date-parts'].is_a?(Array) + data[key]['date-parts'].first + end + end + + date_parts = get_date_parts.call('issued') || + get_date_parts.call('published') || + get_date_parts.call('published-print') + date_parts ? (Date.new(*date_parts) rescue nil) : nil + end + + def build_citation(data) + case data[:type] + when 'book-chapter' + format_crossref_in_collection_citation(data) + when 'book', 'monograph' + format_crossref_book_citation(data) + when 'journal-article' + format_crossref_journal_citation(data) + when 'proceedings-article' + format_crossref_in_collection_citation(data) + when 'proceedings' + format_crossref_proceedings_citation(data) + when 'posted-content' + format_crossref_preprint_citation(data) + else + default_citation(data) + end + end + + + def format_crossref_journal_citation(data) + journal = data[:short_journal_title].presence || data[:journal] + volume = data[:volume].presence + issue = data[:issue].presence + pages = data[:page].presence + article = data[:article_number].presence + + # Build the core part: "Journal 585(7825):357–362" or "J Chem Inf Model:acs.jcim.5c01488" + parts = [journal, volume].compact.join(' ') + parts += "(#{issue})" if issue + parts += ":#{pages || article}." if pages || article + + parts.squish + end + + + #book-chapter + proceedings-article + def format_crossref_in_collection_citation(data) + book_title = data[:booktitle] + publisher = data[:publisher] + location = data[:location].to_s.strip + pages = data[:page] + pages_str = + if pages.present? + pages.to_s.include?('-') || pages.to_s.include?('–') ? ", pp #{pages}" : ", p #{pages}" + else + '' + end + + "In: #{book_title}. #{publisher}#{", #{location}" if location.present?}#{pages_str}".squish + end + + + def format_crossref_book_citation(data) + publisher = data[:publisher] + location = data[:location] || '' + "#{[publisher, location.presence].compact.join(', ')}".squish + end + + def format_crossref_proceedings_citation(data) + + editors = data[:editors] + title = data[:title] + publisher = data[:publisher] + location = data[:location].strip + editor_str = editors.present? ? "#{editors} (eds)" : '' + + citation_parts = [] + citation_parts << "#{editor_str}," if editors.present? + citation_parts << "#{title}. #{publisher}," + citation_parts << location if location.present? + + citation_parts.compact.join(' ').squish + end + + def format_crossref_preprint_citation(data) + + repo = data[:journal] + url = data[:url] + + citation_parts = [] + citation_parts << "Preprint." + citation_parts << "#{repo}." if repo.present? + citation_parts << "#{url}" if url.present? + citation_parts.compact.join(' ').squish + end + + def default_citation(data) + parts = [] + if data[:publisher] + parts << data[:publisher] + end + if data[:url] + parts << data[:url] + end + parts.join('. ') + (parts.empty? ? '' : '.') + end + + end + end + end +end diff --git a/lib/seek/doi/parsers/datacite_parser.rb b/lib/seek/doi/parsers/datacite_parser.rb new file mode 100644 index 0000000000..44fb2a9266 --- /dev/null +++ b/lib/seek/doi/parsers/datacite_parser.rb @@ -0,0 +1,60 @@ +module Seek + module Doi + module Parsers + class DataciteParser < BaseParser + DATACITE_API_ENDPOINT = 'https://api.datacite.org/dois'.freeze + + private + + def build_url(doi) + URI("#{DATACITE_API_ENDPOINT}/#{doi}") + end + + def parse_response_body(response) + json = JSON.parse(response.body) + json.dig('data', 'attributes') + end + + def extract_metadata(data) + { + type: data.dig('types', 'resourceTypeGeneral') || 'unspecified', + title: Array(data['titles']).first&.[]('title'), + abstract: extract_abstract(data), + date_published: extract_date(data)&.to_s, + journal: data.dig('container', 'title'), + doi: data['doi'], + publisher: data['publisher'], + authors: extract_authors_as_objects(data['creators']), + editors: extract_editors(data['contributors']).join(' and '), + url: data['url'], + volume: data.dig('container', 'volume'), + issue: data.dig('container', 'issue'), + page: data.dig('container', 'firstPage'), + location: extract_location(data) + } + end + + def extract_abstract(data) + desc = Array(data['descriptions']).find { |d| d['descriptionType'] == 'Abstract' } + desc&.[]('description')&.strip + end + + def extract_date(data) + if data['publicationYear'] + Date.new(data['publicationYear'].to_i) + elsif (issued = Array(data['dates']).find { |d| d['dateType'] == 'Issued' }) + begin + Date.parse(issued['date']) + rescue + nil + end + end + end + + def extract_location(data) + Array(data['geoLocations']).first&.[]('geoLocationPlace') + end + end + end + end +end diff --git a/test/functional/publications_controller_test.rb b/test/functional/publications_controller_test.rb index f1850a5f56..9783fbbc7d 100644 --- a/test/functional/publications_controller_test.rb +++ b/test/functional/publications_controller_test.rb @@ -62,43 +62,61 @@ def test_title test 'should create doi publication and suggest the associated person' do person = people(:johan_person) - mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1371/journal.pone.0004803', content_file: 'cross_ref3.xml') - assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } + VCR.use_cassette('doi/cross_ref4') do + doi = '10.1371/journal.pone.0004803' + assert_difference('Publication.count') do + post :create, params: { publication: { doi: doi, project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } + end end get :manage, params: { id: assigns(:publication) } assert_response :success p = assigns(:publication) + assert_equal p.publication_authors[0].suggested_person.name, person.name assert_nil p.publication_authors[1].suggested_person end test 'should create doi publication' do - mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1371/journal.pone.0004803', content_file: 'cross_ref3.xml') - assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + VCR.use_cassette('doi/cross_ref1') do + doi = '10.1038/s41586-020-2649-2' + assert_difference('Publication.count') do + post :create, params: { publication: { doi: doi, project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } + end end assert_redirected_to manage_publication_path(assigns(:publication), newly_created: true) end + + + test 'should create an inproceedings with booktitle' do - mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1117/12.2275959', content_file: 'cross_ref6.xml') - assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1117/12.2275959', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:inproceedings).id } } + doi = '10.1117/12.2275959' + + VCR.use_cassette('doi/doi_crossref_proceedings_article_response_1') do + assert_difference('Publication.count') do + post :create, params: { + publication: { + doi: doi, + project_ids: [projects(:sysmo_project).id], + publication_type_id: FactoryBot.create(:inproceedings).id + } + } + end end assert_not_nil assigns(:publication) assert_redirected_to manage_publication_path(assigns(:publication), newly_created: true) - end test 'should create doi publication with various doi prefixes' do - mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1371/journal.pone.0004803', content_file: 'cross_ref3.xml') - assert_difference('Publication.count') do - post :create, params: { publication: { doi: 'DOI: 10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + doi = '10.1371/journal.pone.0004803' + VCR.use_cassette('doi/cross_ref3') do + assert_difference('Publication.count') do + post :create, params: { publication: { doi: "DOI: #{doi}", project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + end end assert_not_nil assigns(:publication) @@ -106,8 +124,10 @@ def test_title assigns(:publication).destroy # formatted slightly different - assert_difference('Publication.count') do - post :create, params: { publication: { doi: 'doi:10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + VCR.use_cassette('doi/cross_ref3') do + assert_difference('Publication.count') do + post :create, params: { publication: { doi: "doi: #{doi}", project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + end end assert_not_nil assigns(:publication) @@ -115,8 +135,10 @@ def test_title assigns(:publication).destroy # with url - assert_difference('Publication.count') do - post :create, params: { publication: { doi: 'https://doi.org/10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + VCR.use_cassette('doi/cross_ref3') do + assert_difference('Publication.count') do + post :create, params: { publication: { doi: "https://doi.org/#{doi}", project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + end end assert_not_nil assigns(:publication) @@ -124,8 +146,10 @@ def test_title assigns(:publication).destroy # with url but no protocol - assert_difference('Publication.count') do - post :create, params: { publication: { doi: 'doi.org/10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + VCR.use_cassette('doi/cross_ref3') do + assert_difference('Publication.count') do + post :create, params: { publication: { doi: "doi.org/#{doi}", project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + end end assert_not_nil assigns(:publication) @@ -133,8 +157,10 @@ def test_title assigns(:publication).destroy # also test with spaces around - assert_difference('Publication.count') do - post :create, params: { publication: { doi: ' 10.1371/journal.pone.0004803 ', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + VCR.use_cassette('doi/cross_ref3') do + assert_difference('Publication.count') do + post :create, params: { publication: { doi: " #{doi} ", project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + end end assert_redirected_to manage_publication_path(assigns(:publication), newly_created: true) @@ -197,22 +223,22 @@ def test_title test 'should import multiple from bibtex file' do publications = [ - { - #publications[0] - title: 'Taverna: a tool for building and running workflows of services.', - journal: 'Nucleic Acids Res', - published_date: Date.new(2006), - publication_type: FactoryBot.create(:journal), - authors: [ - PublicationAuthor.new(first_name: 'D.', last_name: 'Hull', author_index: 0), - PublicationAuthor.new(first_name: 'K.', last_name: 'Wolstencroft', author_index: 1), - PublicationAuthor.new(first_name: 'R.', last_name: 'Stevens', author_index: 2), - PublicationAuthor.new(first_name: 'C.', last_name: 'Goble', author_index: 3), - PublicationAuthor.new(first_name: 'M. R.', last_name: 'Pocock', author_index: 4), - PublicationAuthor.new(first_name: 'P.', last_name: 'Li', author_index: 5), - PublicationAuthor.new(first_name: 'T.', last_name: 'Oinn', author_index: 6) - ] - }, + { + #publications[0] + title: 'Taverna: a tool for building and running workflows of services.', + journal: 'Nucleic Acids Res', + published_date: Date.new(2006), + publication_type: FactoryBot.create(:journal), + authors: [ + PublicationAuthor.new(first_name: 'D.', last_name: 'Hull', author_index: 0), + PublicationAuthor.new(first_name: 'K.', last_name: 'Wolstencroft', author_index: 1), + PublicationAuthor.new(first_name: 'R.', last_name: 'Stevens', author_index: 2), + PublicationAuthor.new(first_name: 'C.', last_name: 'Goble', author_index: 3), + PublicationAuthor.new(first_name: 'M. R.', last_name: 'Pocock', author_index: 4), + PublicationAuthor.new(first_name: 'P.', last_name: 'Li', author_index: 5), + PublicationAuthor.new(first_name: 'T.', last_name: 'Oinn', author_index: 6) + ] + }, { #publications[1] title: 'Yet another tool for importing publications', @@ -220,7 +246,7 @@ def test_title published_date: Date.new(2016), publication_type: FactoryBot.create(:journal), authors: [ - PublicationAuthor.new(first_name: 'J.', last_name: 'Shmoe', author_index: 0), + PublicationAuthor.new(first_name: 'J.', last_name: 'Shmoe', author_index: 0), PublicationAuthor.new(first_name: 'M.', last_name: 'Mustermann', author_index: 1) ] }, @@ -230,14 +256,15 @@ def test_title published_date: Date.new(2016), publication_type: FactoryBot.create(:phdthesis), authors: [ - PublicationAuthor.new(first_name: 'J.', last_name: 'Shmoe', author_index: 0), + PublicationAuthor.new(first_name: 'J.', last_name: 'Shmoe', author_index: 0), ] } ] - - assert_difference('Publication.count', 3) do + VCR.use_cassette('doi/cross_ref6') do + assert_difference('Publication.count', 3) do post :create, params: { subaction: 'ImportMultiple', publication: { bibtex_file: fixture_file_upload('publications.bibtex'), project_ids: [projects(:one).id] } } + end end publication0 = Publication.where(title: publications[0][:title]).first @@ -286,16 +313,16 @@ def test_title test 'should associate authors to users when importing multiple publications from bibtex files' do publications = [ - { - #publications[0] - title: 'Taverna: a tool for building and running workflows of services.', - journal: 'Nucleic Acids Res', - published_date: Date.new(2006), - publication_type: FactoryBot.create(:journal), - authors: [ - PublicationAuthor.new(first_name: 'quentin', last_name: 'Jones', author_index: 0), - PublicationAuthor.new(first_name: 'aaron', last_name: 'spiggle', author_index: 1)] - }, + { + #publications[0] + title: 'Taverna: a tool for building and running workflows of services.', + journal: 'Nucleic Acids Res', + published_date: Date.new(2006), + publication_type: FactoryBot.create(:journal), + authors: [ + PublicationAuthor.new(first_name: 'quentin', last_name: 'Jones', author_index: 0), + PublicationAuthor.new(first_name: 'aaron', last_name: 'spiggle', author_index: 1)] + }, { #publications[1] title: 'This is a real publication', @@ -303,7 +330,7 @@ def test_title published_date: Date.new(2015), publication_type: FactoryBot.create(:journal), authors: [ - PublicationAuthor.new(first_name: 'Alice', last_name: 'Gräter', author_index: 0), + PublicationAuthor.new(first_name: 'Alice', last_name: 'Gräter', author_index: 0), PublicationAuthor.new(first_name: 'Bob', last_name: 'Mueller', author_index: 1) ] } @@ -896,21 +923,20 @@ def test_title end test "shouldn't add paper with non-unique title within the same project" do - mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1093/nar/gkl320', content_file: 'cross_ref4.xml') - pub = Publication.find_by_doi('10.1093/nar/gkl320') - - # PubMed version of publication already exists, so it shouldn't re-add - assert_no_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1093/nar/gkl320', projects: pub.projects.first } } if pub + VCR.use_cassette('doi/cross_ref4') do + pub = Publication.find_by_doi('10.1093/nar/gkl320') + # PubMed version of publication already exists, so it shouldn't re-add + assert_no_difference('Publication.count') do + post :create, params: { publication: { doi: '10.1093/nar/gkl320', projects: pub.projects.first } } if pub + end end end test 'should retrieve the right author order after a publication is created and after some authors are associate/disassociated with seek profiles' do - mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1016/j.future.2011.08.004', content_file: 'cross_ref5.xml') - assert_difference('Publication.count') do - - post :create, params: { publication: { doi: '10.1016/j.future.2011.08.004', project_ids: [projects(:sysmo_project).id], publication_type_id: FactoryBot.create(:journal).id } } - + VCR.use_cassette('doi/cross_ref5') do + assert_difference('Publication.count') do + post :create, params: { publication: { doi: '10.1016/j.future.2011.08.004', project_ids: [projects(:sysmo_project).id], publication_type_id: FactoryBot.create(:journal).id } } + end end publication = assigns(:publication) original_authors = ['Sean Bechhofer', 'Iain Buchan', 'David De Roure', 'Paolo Missier', 'John Ainsworth', 'Jiten Bhagat', 'Philip Couch', 'Don Cruickshank', @@ -934,24 +960,25 @@ def test_title publication.reload authors = publication.publication_authors.map { |pa| pa.first_name + ' ' + pa.last_name } assert_equal original_authors, authors - + VCR.use_cassette('doi/cross_ref5') do # Disassociate seek-authors assert_difference('publication.non_seek_authors.count', 2) do assert_difference('AssetsCreator.count', -2) do post :disassociate_authors, params: { id: publication.id } end end - + end publication.reload authors = publication.publication_authors.map { |pa| pa.first_name + ' ' + pa.last_name } assert_equal original_authors, authors + end test 'should display the right author order after some authors are associate with seek-profiles' do - doi_citation_mock - mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1016/j.future.2011.08.004', content_file: 'cross_ref5.xml') - assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1016/j.future.2011.08.004', project_ids: [projects(:sysmo_project).id], publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + VCR.use_cassette('doi/cross_ref5') do + assert_difference('Publication.count') do + post :create, params: { publication: { doi: '10.1016/j.future.2011.08.004', project_ids: [projects(:sysmo_project).id], publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + end end assert assigns(:publication) publication = assigns(:publication) @@ -969,15 +996,19 @@ def test_title assert_difference('publication.non_seek_authors.count', -2) do assert_difference('AssetsCreator.count', 2) do put :update, params: { id: publication.id, publication: { - abstract: publication.abstract, - publication_authors_attributes: { '0' => { id: publication.non_seek_authors[12].id, person_id: seek_author1.id }, - '1' => { id: publication.non_seek_authors[15].id, person_id: seek_author2.id } } } } + abstract: publication.abstract, + publication_authors_attributes: { '0' => { id: publication.non_seek_authors[12].id, person_id: seek_author1.id }, + '1' => { id: publication.non_seek_authors[15].id, person_id: seek_author2.id } } } } end end publication.reload joined_original_authors = original_authors.join(', ') - get :show, params: { id: publication.id } + + VCR.use_cassette('doi/cross_ref7') do + get :show, params: { id: publication.id } + end assert @response.body.include?(joined_original_authors) + end test 'should avoid XSS in association forms' do @@ -1151,10 +1182,8 @@ def test_title end test 'should fetch doi preview' do - VCR.use_cassette('publications/fairdom_by_doi') do - with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: '10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: FactoryBot.create(:journal).id } } - end + VCR.use_cassette('doi/cross_ref2') do + post :fetch_preview, xhr: true, params: { key: '10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: FactoryBot.create(:journal).id } } end assert_response :success @@ -1162,10 +1191,8 @@ def test_title end test 'should handle blank pubmed' do - VCR.use_cassette('publications/fairdom_by_doi') do - with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: ' ', protocol: 'pubmed', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: FactoryBot.create(:journal).id } } - end + VCR.use_cassette('doi/cross_ref2') do + post :fetch_preview, xhr: true, params: { key: ' ', protocol: 'pubmed', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: FactoryBot.create(:journal).id } } end assert_response :internal_server_error @@ -1173,10 +1200,8 @@ def test_title end test 'should handle blank doi' do - VCR.use_cassette('publications/fairdom_by_doi') do - with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: ' ', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } - end + VCR.use_cassette('doi/cross_ref2') do + post :fetch_preview, xhr: true, params: { key: ' ', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } end assert_response :internal_server_error @@ -1184,28 +1209,22 @@ def test_title end test 'should fetch doi preview with prefixes' do - VCR.use_cassette('publications/fairdom_by_doi') do - with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: 'doi: 10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } - end + VCR.use_cassette('doi/cross_ref2') do + post :fetch_preview, xhr: true, params: { key: 'doi: 10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } end assert_response :success assert response.body.include?('FAIRDOMHub: a repository') - VCR.use_cassette('publications/fairdom_by_doi') do - with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: 'doi.org/10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } - end + VCR.use_cassette('doi/cross_ref2') do + post :fetch_preview, xhr: true, params: { key: 'doi.org/10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } end assert_response :success assert response.body.include?('FAIRDOMHub: a repository') - VCR.use_cassette('publications/fairdom_by_doi') do - with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: 'https://doi.org/10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } - end + VCR.use_cassette('doi/cross_ref2') do + post :fetch_preview, xhr: true, params: { key: 'https://doi.org/10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } end assert_response :success @@ -1522,7 +1541,7 @@ def test_title assert_difference('AssetLink.misc_link.count') do assert_difference('Publication.count') do - post :create, params: { subaction: 'Create', publication: publication_attrs } + post :create, params: { subaction: 'Create', publication: publication_attrs } end end publication = assigns(:publication) diff --git a/test/unit/doi/crossref_parser_test.rb b/test/unit/doi/crossref_parser_test.rb new file mode 100644 index 0000000000..0b930541d1 --- /dev/null +++ b/test/unit/doi/crossref_parser_test.rb @@ -0,0 +1,279 @@ +require 'test_helper' + +module Seek + module Doi + class CrossrefParserTest < ActiveSupport::TestCase + + + test 'get_doi_ra returns Crossref for a known DOI' do + VCR.use_cassette('doi/crossref_ra') do + doi = '10.1038/s41586-020-2649-2' + ra = Seek::Doi::Parser.send(:get_doi_ra, doi) + assert_equal 'Crossref', ra + end + end + + + # === JOURNAL === + test 'returns parsed journal article DOI (crossref)_1' do + VCR.use_cassette('doi/doi_crossref_journal_article_response_1') do + doi = '10.1038/s41586-020-2649-2' + result = Seek::Doi::Parser.parse(doi) + assert_equal result.title,'Array programming with NumPy' + assert_equal result.type,'journal-article' + assert_equal result.doi, doi + assert_equal result.abstract,'AbstractArray programming provides a powerful, compact and expressive syntax for accessing, manipulating and operating on data in vectors, matrices and higher-dimensional arrays. NumPy is the primary array programming library for the Python language. It has an essential role in research analysis pipelines in fields as diverse as physics, chemistry, astronomy, geoscience, biology, psychology, materials science, engineering, finance and economics. For example, in astronomy, NumPy was an important part of the software stack used in the discovery of gravitational waves1and in the first imaging of a black hole2. Here we review how a few fundamental array concepts lead to a simple and powerful programming paradigm for organizing, exploring and analysing scientific data. NumPy is the foundation upon which the scientific Python ecosystem is constructed. It is so pervasive that several projects, targeting audiences with specialized needs, have developed their own NumPy-like interfaces and array objects. Owing to its central position in the ecosystem, NumPy increasingly acts as an interoperability layer between such array computation libraries and, together with its application programming interface (API), provides a flexible framework to support the next decade of scientific and industrial analysis.' + assert_equal result.journal, 'Nature' + assert_equal result.publisher, 'Springer Science and Business Media LLC' + assert_equal result.date_published, '2020-09-16' + assert_equal result.authors.first.full_name, 'Charles R. Harris' + assert_equal result[:citation], 'Nature 585(7825):357-362.' + assert_equal result.url, 'https://doi.org/10.1038/s41586-020-2649-2' + end + end + + test 'returns parsed journal article DOI (crossref)_2' do + VCR.use_cassette('doi/doi_crossref_journal_article_response_2') do + doi = '10.1021/acs.jcim.5c01488' + result = Seek::Doi::Parser.parse(doi) + + assert_equal 'journal-article', result.type + assert_equal 'A Multiscale Simulation Approach to Compute Protein–Ligand Association Rate Constants by Combining Brownian Dynamics and Molecular Dynamics', result.title + assert_equal doi, result.doi + assert_nil result.abstract + assert_equal 'Abraham Muñiz-Chicharro', result.authors[0].full_name + assert_equal 'Gaurav K. Ganotra', result.authors[1].full_name + assert_equal 'Rebecca C. Wade', result.authors[2].full_name + assert_empty result.editors + assert_equal 'American Chemical Society (ACS)', result.publisher + assert_equal '2025-10-04', result.date_published + assert_equal 'Journal of Chemical Information and Modeling', result.booktitle + assert_equal 'Journal of Chemical Information and Modeling', result.journal + assert_equal 'https://doi.org/10.1021/acs.jcim.5c01488', result.url + assert_equal 'J. Chem. Inf. Model. 65(20):11215-11231.', result.citation + + end + end + + + # === MONOGRAPH === + test 'returns parsed journal article DOI with editors and subtitle (crossref)' do + VCR.use_cassette('doi/doi_crossref_book_with_editor_subtitle_response') do + doi = '10.2307/j.ctvn5txvs' + result = Seek::Doi::Parser.parse(doi) + assert_equal result.type, 'monograph' + assert_equal result.title, 'Troy Book:Selections' + assert_equal result.doi, doi + assert_nil result.abstract + assert_nil result.journal + assert_equal result.authors.first.full_name, 'John Lydgate' + assert_equal result.editors, 'Robert R. Edwards' + assert_equal result.publisher, 'Medieval Institute Publications' + assert_equal result.url, 'https://doi.org/10.2307/j.ctvn5txvs' + assert_equal result.date_published, '1998-03-01' + assert_equal result[:citation], 'Medieval Institute Publications' + end + end + + # === PROCEEDINGS ARTICLE === + test 'returns parsed proceedings article DOI (crossref)_1' do + VCR.use_cassette('doi/doi_crossref_proceedings_article_response_1') do + doi = '10.1117/12.2275959' + result = Seek::Doi::Parser.parse(doi) + assert_equal result.type, 'proceedings-article' + assert_equal result.title, 'The NOVA project: maximizing beam time efficiency through synergistic analyses of SRμCT data' + assert_equal result.doi, doi + assert_nil result.abstract + assert_equal result.journal, 'Developments in X-Ray Tomography XI' + assert_equal result.authors.first.full_name, 'Sebastian Schmelzle' + assert_equal result.editors, 'Bert Müller and Ge Wang' + assert_equal result.publisher, 'SPIE' + assert_equal result.url, 'https://doi.org/10.1117/12.2275959' + assert_equal result.date_published, '2017-09-26' + assert_equal result.citation, 'In: Developments in X-Ray Tomography XI. SPIE, San Diego, United States, p 24' + end + end + + + test 'returns parsed proceedings article DOI (crossref)_2' do + VCR.use_cassette('doi/doi_crossref_proceedings_article_response_2') do + doi = '10.1145/3292500.3330675' + result = Seek::Doi::Parser.parse(doi) + assert_equal 'proceedings-article', result.type + assert_equal 'Whole Page Optimization with Global Constraints', result.title + assert_equal doi, result.doi + assert_nil result.abstract + assert_equal 'Weicong Ding', result.authors[0].full_name + assert_equal 3, result.authors.size + assert_empty result.editors + assert_equal 'ACM', result.publisher + assert_equal '2019-07-25', result.date_published + assert_equal 'Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining', result.booktitle + assert_equal 'Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining', result.journal + assert_equal '3153-3161', result.page + assert_equal 'https://doi.org/10.1145/3292500.3330675', result.url + assert_equal 'In: Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining. ACM, Anchorage AK USA, pp 3153-3161', result.citation + + end + end + + test 'returns parsed proceedings article DOI (crossref)_3' do + VCR.use_cassette('doi/doi_crossref_proceedings_article_response_3') do + doi = '10.1063/1.2128263' + result = Seek::Doi::Parser.parse(doi) + assert_equal 'proceedings-article', result.type + assert_equal 'Conference Recommendations', result.title + assert_equal doi, result.doi + assert_nil result.abstract + assert_equal 'Conference organizers ', result.authors.first.full_name + assert_empty result.editors + assert_equal 'AIP', result.publisher + assert_equal '2005-01-01', result.date_published + assert_equal 'AIP Conference Proceedings', result.booktitle + assert_equal 'AIP Conference Proceedings', result.journal + assert_equal '29-34', result.page + assert_equal 'https://doi.org/10.1063/1.2128263', result.url + assert_equal 'In: AIP Conference Proceedings. AIP, Rio de Janeiro (Brazil), pp 29-34', result.citation + end + end + + # === PROCEEDINGS === + test 'returns parsed proceedings DOI (crossref)_1' do + VCR.use_cassette('doi/doi_crossref_proceedings_response_1') do + doi = '10.18653/v1/w18-08' + result = Seek::Doi::Parser.parse(doi) + assert_equal result.type, 'proceedings' + assert_equal 'Proceedings of the Second ACL Workshop on Ethics in Natural Language Processing', result.title + assert_equal doi, result.doi + assert_equal 'Association for Computational Linguistics', result.publisher + assert_equal '2018-01-01', result.date_published + assert_equal 'https://doi.org/10.18653/v1/w18-08', result.url + assert_equal 'Proceedings of the Second ACL Workshop on Ethics in Natural Language Processing. Association for Computational Linguistics, New Orleans, Louisiana, USA', result.citation + end + end + + + + # === BOOK CHAPTER === + test 'parses book chapter DOI (Crossref)_1' do + VCR.use_cassette('doi/doi_crossref_book_chapter_response_1') do + doi = '10.1007/978-3-642-16239-8_8' + result = Seek::Doi::Parser.parse(doi) + assert_equal 'book-chapter', result.type + assert_equal 'Prediction with Confidence Based on a Random Forest Classifier', result.title + assert_equal doi, result.doi + assert_nil result.abstract + assert_equal 'Dmitry Devetyarov', result.authors.first.full_name + assert_equal 'Ilia Nouretdinov', result.authors.last.full_name + assert_empty result.editors + assert_equal 'Springer Berlin Heidelberg', result.publisher + assert_equal '2010-01-01', result.date_published + assert_equal 'https://doi.org/10.1007/978-3-642-16239-8_8', result.url + assert_equal "In: Artificial Intelligence Applications and Innovations. Springer Berlin Heidelberg, Berlin, Heidelberg, pp 37-44", result.citation + end + end + + test 'parses book chapter DOI (Crossref)_2' do + VCR.use_cassette('doi/doi_crossref_book_chapter_response_2') do + doi = '10.1007/978-3-540-70504-8_9' + result = Seek::Doi::Parser.parse(doi) + assert_equal result.type, 'book-chapter' + assert_equal 'book-chapter', result.type + assert_equal 'A Semantics for a Query Language over Sensors, Streams and Relations', result.title + assert_equal doi, result.doi + assert_nil result.abstract + assert_equal 4, result.authors.size + assert_equal 'Christian Y. A. Brenninkmeijer', result.authors[0].full_name + assert_empty result.editors + assert_equal 'Springer Berlin Heidelberg', result.publisher + assert_equal 'Sharing Data, Information and Knowledge', result.booktitle + assert_equal 'Sharing Data, Information and Knowledge', result.journal + assert_equal '87-99', result.page + assert_equal 'https://doi.org/10.1007/978-3-540-70504-8_9', result.url + assert_equal 'In: Sharing Data, Information and Knowledge. Springer Berlin Heidelberg, Berlin, Heidelberg, pp 87-99', result.citation + end + end + + test 'parses book chapter DOI (Crossref)_3' do + VCR.use_cassette('doi/doi_crossref_book_chapter_response_3') do + doi = '10.1007/978-3-642-16239-8_8' + result = Seek::Doi::Parser.parse(doi) + assert_equal 'book-chapter', result.type + assert_equal 'Prediction with Confidence Based on a Random Forest Classifier', result.title + assert_equal doi, result.doi + assert_nil result.abstract + assert_equal 2, result.authors.size + assert_equal 'Dmitry Devetyarov', result.authors.first.full_name + assert_empty result.editors + assert_equal 'Springer Berlin Heidelberg', result.publisher + assert_equal '2010-01-01', result.date_published + assert_equal 'https://doi.org/10.1007/978-3-642-16239-8_8', result.url + assert_equal 'Artificial Intelligence Applications and Innovations', result.booktitle + assert_equal 'Artificial Intelligence Applications and Innovations', result.journal + assert_equal '37-44', result.page + assert_equal 'In: Artificial Intelligence Applications and Innovations. Springer Berlin Heidelberg, Berlin, Heidelberg, pp 37-44', result.citation + + end + end + + + # === BOOK === + # more book doi: 10.1007/978-3-662-49096-9 + test 'parses book DOI (Crossref)_1' do + VCR.use_cassette('doi/doi_crossref_book_response_1') do + doi = '10.23943/princeton/9780691161914.003.0002' + result = Seek::Doi::Parser.parse(doi) + assert_equal 'book', result.type + assert_equal "Milton’s Book of Numbers: Book 1 and Its Catalog", result.title + assert_equal doi, result.doi + assert_match(/Paradise Lost/, result.abstract) + assert_equal 'David Quint', result.authors.first.full_name + assert_equal 1, result.authors.size + assert_empty result.editors + assert_equal 'Princeton University Press', result.publisher + assert_equal '2017-10-19', result.date_published + assert_equal 'Princeton University Press', result.booktitle + assert_equal 'Princeton University Press', result.journal + assert_equal 'https://doi.org/10.23943/princeton/9780691161914.003.0002', result.url + assert_equal 'Princeton University Press', result.citation + end + end + + test 'parses book DOI (Crossref)_2' do + VCR.use_cassette('doi/doi_crossref_book_response_2') do + doi = '10.1007/978-3-540-70504-8' + result = Seek::Doi::Parser.parse(doi) + assert_equal 'book', result.type + assert_equal 'Sharing Data, Information and Knowledge:25th British National Conference on Databases, BNCOD 25, Cardiff, UK, July 7-10, 2008. Proceedings', result.title + assert_equal doi, result.doi + assert_nil result.abstract + assert_empty result.authors + assert_equal 'Alex Gray and Keith Jeffery and Jianhua Shao', result.editors + assert_equal 'Springer Berlin Heidelberg', result.publisher + assert_equal '2008-01-01', result.date_published + assert_equal 'Lecture Notes in Computer Science', result.booktitle + assert_equal 'Lecture Notes in Computer Science', result.journal + assert_equal 'https://doi.org/10.1007/978-3-540-70504-8', result.url + assert_equal 'Springer Berlin Heidelberg, Berlin, Heidelberg', result.citation + end + end + + + # === PREPRINT === + + test 'parses preprint DOI (Crossref)_1' do + VCR.use_cassette('doi/doi_crossref_preprint_response_1') do + doi = '10.20944/preprints201909.0043.v1' + result = Seek::Doi::Parser.parse(doi) + assert_equal 'posted-content', result.type + assert_equal 'An Isolated Complex V Inefficiency and Dysregulated Mitochondrial Function in Immortalized Lymphocytes from ME/CFS Patients', result.title + assert_equal doi, result.doi + assert_equal 'https://doi.org/10.20944/preprints201909.0043.v1', result.url + assert_equal '2019-09-04', result.date_published + assert_equal 'Preprint. https://doi.org/10.20944/preprints201909.0043.v1', result.citation + end + end + end + end +end + diff --git a/test/unit/doi/datacite_parser_test.rb b/test/unit/doi/datacite_parser_test.rb new file mode 100644 index 0000000000..2c71521054 --- /dev/null +++ b/test/unit/doi/datacite_parser_test.rb @@ -0,0 +1,58 @@ +require 'test_helper' + +class Seek::Doi::DataciteParserTest < ActiveSupport::TestCase + + test 'get_doi_ra returns DataCite for a known DOI' do + VCR.use_cassette('doi/datacite_ra') do + doi = '10.5281/zenodo.16736322' + ra = Seek::Doi::Parser.send(:get_doi_ra, doi) + assert_equal 'DataCite', ra + end + end + + + # === Conference Paper === + test 'parses DOI (DataCite)_1' do + VCR.use_cassette('doi/doi_datacite_response_1') do + doi = '10.5281/zenodo.16736322' + result = Seek::Doi::Parser.parse(doi) + assert_equal result.title,'Flexible Metadata Structuring for Research Data Management Through the FAIRDOM-SEEK Platform - Implementing Tailored and Complex Metadata Schemes in SEEK' + assert_equal result.type,'ConferencePaper' + assert_equal result.doi, doi + assert_match /Modern research projects increasingly require/, result.abstract + assert_equal result.publisher, 'Zenodo' + assert_equal result.date_published, '2025-01-01' + assert_equal result.authors.first.full_name, 'Xiaoming Hu' + assert_equal result.authors.size, 7 + assert_equal result.url, 'https://zenodo.org/doi/10.5281/zenodo.16736322' + puts result.citation.inspect + end + end + + # === DataSet === + test 'parses DOI (DataCite)_2' do + VCR.use_cassette('doi/doi_datacite_response_2') do + doi = '10.5061/dryad.m62gj' + result = Seek::Doi::Parser.parse(doi) + assert_equal result.title, 'Data from: The hydrological legacy of deforestation on global wetlands' + assert_equal result.type,'Dataset' + assert_equal result.doi, doi + assert_equal result.citation, 'Dryad. https://datadryad.org/dataset/doi:10.5061/dryad.m62gj.' + end + end + + # === Text === + #Li S, Gong M, Li Y-H, et al (2024) High spin axion insulator. arXiv. https://doi.org/10.48550/ARXIV.2404.12345 + test 'parses DOI (DataCite)_3' do + VCR.use_cassette('doi/doi_datacite_response_3') do + doi = '10.48550/arxiv.2404.12345' + result = Seek::Doi::Parser.parse(doi) + assert_equal result.title, 'High spin axion insulator' + assert_equal result.type,'Text' + assert_equal result.doi, doi + assert_equal result.citation, 'arXiv. https://arxiv.org/abs/2404.12345.' + end + end + +end + diff --git a/test/unit/doi/doi_parser_exception_test.rb b/test/unit/doi/doi_parser_exception_test.rb new file mode 100644 index 0000000000..a6940fdb58 --- /dev/null +++ b/test/unit/doi/doi_parser_exception_test.rb @@ -0,0 +1,63 @@ +require 'test_helper' + +class DoiParserExceptionTest < ActiveSupport::TestCase + + test 'mEDRA DOI is detected' do + VCR.use_cassette('doi/medra_ra') do + doi = '10.19232/uv4pb.2018.2.00' + assert_equal 'mEDRA', Seek::Doi::Parser.send(:get_doi_ra, doi) + end + end + + # Test that a DOI registered under mEDRA raises the correct exception + test 'parsing mEDRA DOI raises RANotSupported' do + VCR.use_cassette('doi/medra_ra') do + doi = '10.19232/uv4pb.2018.2.00' + error = assert_raises(Seek::Doi::RANotSupported) do + Seek::Doi::Parser.parse(doi) + end + assert_equal "DOI registration agency 'mEDRA' is not supported.", error.message + end + end + + + test 'raises NotFoundException for fake DOI' do + VCR.use_cassette('doi/fake_doi') do + doi = '10.19232/fake.2020.1.23' + error = assert_raises(Seek::Doi::NotFoundException) do + Seek::Doi::Parser.send(:get_doi_ra, doi) + end + assert_equal 'DOI does not exist: 10.19232/fake.2020.1.23.', error.message + end + end + + test 'raises MalformedDOIException for invalid DOI' do + VCR.use_cassette('doi/invalid_doi') do + doi = 'hello_march' + error = assert_raises(Seek::Doi::MalformedDOIException) do + Seek::Doi::Parser.send(:get_doi_ra, doi) + end + assert_equal 'Invalid DOI format: hello_march.', error.message + end + end + + + test 'raises ParseException when Crossref returns invalid JSON' do + doi = '10.1016/j.patter.2025.101345' + + VCR.use_cassette('doi/invalid_json_response') do + error = assert_raises(Seek::Doi::ParseException) do + Seek::Doi::Parser.parse(doi) + end + assert_match /Error parsing JSON for DOI/, error.message + end + end + +end + + +# resource not found +#10.31234/osf.io/8s4xq + +# phd thesis can not be resolved +#10.5445/IR/1000055628 \ No newline at end of file diff --git a/test/unit/feed_reader_test.rb b/test/unit/feed_reader_test.rb index bb83212d7e..5cd1626abe 100644 --- a/test/unit/feed_reader_test.rb +++ b/test/unit/feed_reader_test.rb @@ -66,8 +66,6 @@ def teardown end test 'handles error and ignores bad feed' do - XML::Error.set_handler(&XML::Error::QUIET_HANDLER) - VCR.use_cassette('feedjira/get_bad_feed') do Seek::Config.project_news_feed_urls = "#{bad_feed_url}" Seek::Config.project_news_number_of_entries = 5 diff --git a/test/unit/publication_test.rb b/test/unit/publication_test.rb index f9d4752d38..334b9eb21d 100644 --- a/test/unit/publication_test.rb +++ b/test/unit/publication_test.rb @@ -1,4 +1,5 @@ require 'test_helper' +require 'minitest/mock' class PublicationTest < ActiveSupport::TestCase include MockHelper @@ -50,27 +51,37 @@ class PublicationTest < ActiveSupport::TestCase assert_nil publication.doi end - test 'create publication from metadata doi' do - publication_hash = { - title: 'SEEK publication', - abstract: 'An investigation into blalblabla', - journal: 'The testing journal', - date_published: Date.new(2011, 12, 24), - pubmed_id: nil, - doi: nil - } - doi_record = DOI::Record.new(publication_hash) - publication = Publication.new - publication.extract_doi_metadata(doi_record) - assert_equal publication_hash[:title], publication.title - assert_equal publication_hash[:journal], publication.journal - assert_equal publication_hash[:date_published], publication.published_date - assert_equal publication_hash[:abstract], publication.abstract - assert_nil publication.pubmed_id - assert_nil publication.doi - assert_equal Publication::REGISTRATION_BY_DOI, publication.registered_mode + test 'create publication from metadata via Seek::Doi::Parser' do + + # Simulate parser result — OpenStruct-like metadata + parsed_record = OpenStruct.new( + title: 'SEEK publication', + abstract: 'An investigation into blalblabla', + journal: 'The testing journal', + date_published: Date.new(2011, 12, 24), + pubmed_id: nil, + doi: nil, + citation: nil, + publisher: 'The Testing Publisher', + booktitle: nil, + editors: nil + ) + + # Stub the parser call to return the fake metadata + Seek::Doi::Parser.stub(:parse, parsed_record) do + publication = Publication.new + publication.extract_doi_metadata(parsed_record) + assert_equal 'SEEK publication', publication.title + assert_equal 'The testing journal', publication.journal + assert_equal Date.new(2011, 12, 24), publication.published_date + assert_equal 'An investigation into blalblabla', publication.abstract + assert_nil publication.pubmed_id + assert_nil publication.doi + assert_equal Publication::REGISTRATION_BY_DOI, publication.registered_mode + end end + test 'create publication from metadata pubmed' do publication_hash = { 'title' => 'SEEK publication\\r', # test required? chomp @@ -220,58 +231,72 @@ class PublicationTest < ActiveSupport::TestCase end test 'book chapter doi' do - mock_crossref(email: 'fred@email.com', doi: '10.1007/978-3-642-16239-8_8', content_file: 'cross_ref1.xml') - query = DOI::Query.new('fred@email.com') - result = query.fetch('10.1007/978-3-642-16239-8_8') - assert_equal :book_chapter, result.publication_type - assert_equal 'Prediction with Confidence Based on a Random Forest Classifier', result.title - assert_equal 2, result.authors.size - assert_equal 'Artificial Intelligence Applications and Innovations 339:37-44,Springer Berlin Heidelberg', result.citation - last_names = %w(Devetyarov Nouretdinov) - result.authors.each do |auth| - assert last_names.include? auth.last_name + VCR.use_cassette('doi/doi_crossref_book_chapter_response_3') do + result = Seek::Doi::Parser.parse('10.1007/978-3-642-16239-8_8') + assert_equal 'book-chapter', result.type + assert_equal 'Prediction with Confidence Based on a Random Forest Classifier', result.title + assert_equal 2, result.authors.size + assert_equal 'In: Artificial Intelligence Applications and Innovations. Springer Berlin Heidelberg, Berlin, Heidelberg, pp 37-44', result.citation + last_names = %w(Devetyarov Nouretdinov) + result.authors.each do |auth| + assert last_names.include? auth.last_name + end + + assert_equal 'Artificial Intelligence Applications and Innovations', result.journal + assert_equal '2010-01-01', result.date_published + assert_equal '10.1007/978-3-642-16239-8_8', result.doi + assert_nil result.error + end - assert_equal 'Artificial Intelligence Applications and Innovations', result.journal - assert_equal Date.parse('1 Jan 2010'), result.date_published - assert_equal '10.1007/978-3-642-16239-8_8', result.doi - assert_nil result.error end - test 'doi with not resolvable error' do - mock_crossref(email: 'fred@email.com', doi: '10.4230/OASIcs.GCB.2012.1', content_file: 'cross_ref_no_resolve.xml') - assert_raises DOI::NotFoundException do - query = DOI::Query.new('fred@email.com') - query.fetch('10.4230/OASIcs.GCB.2012.1') + + test 'raises NotFoundException for fake DOI' do + VCR.use_cassette('doi/fake_doi') do + doi = '10.19232/fake.2020.1.23' + error = assert_raises(Seek::Doi::NotFoundException) do + Seek::Doi::Parser.send(:get_doi_ra, doi) + end + assert_equal 'DOI does not exist: 10.19232/fake.2020.1.23.', error.message end end - test 'malformed doi' do - mock_crossref(email: 'fred@email.com', doi: '10.1.11.1', content_file: 'cross_ref_malformed_doi.html') - assert_raises DOI::MalformedDOIException do - query = DOI::Query.new('fred@email.com') - query.fetch('10.1.11.1') + test 'raises MalformedDOIException for invalid DOI' do + VCR.use_cassette('doi/invalid_doi') do + doi = 'hello_march' + error = assert_raises(Seek::Doi::MalformedDOIException) do + Seek::Doi::Parser.send(:get_doi_ra, doi) + end + assert_equal 'Invalid DOI format: hello_march.', error.message end end - test 'unsupported type doi' do - mock_crossref(email: 'fred@email.com', doi: '10.1.11.1', content_file: 'cross_ref_unsupported_type.xml') - assert_raises DOI::RecordNotSupported do - query = DOI::Query.new('fred@email.com') - query.fetch('10.1.11.1') + + test 'raises ParseException when Crossref returns invalid JSON' do + doi = '10.1016/j.patter.2025.101345' + + VCR.use_cassette('doi/invalid_json_response') do + error = assert_raises(Seek::Doi::ParseException) do + Seek::Doi::Parser.parse(doi) + end + assert_match /Error parsing JSON for DOI/, error.message end end - test 'editor should not be author' do - mock_crossref(email: 'fred@email.com', doi: '10.1371/journal.pcbi.1002352', content_file: 'cross_ref2.xml') - query = DOI::Query.new('fred@email.com') - result = query.fetch('10.1371/journal.pcbi.1002352') - assert result.error.nil?, 'There should not be an error' - assert !result.authors.collect(&:last_name).include?('Papin') - assert_equal 5, result.authors.size - assert_nil result.error + test 'Crossref entry should not list editors as authors' do + VCR.use_cassette('doi/cross_ref8') do + doi = '10.1371/journal.pcbi.1002352' + + result = Seek::Doi::Parser.parse(doi) + + assert result.respond_to?(:authors), 'Expected parser result to include authors' + refute_includes result.authors.map(&:last_name), 'Papin', 'Editor should not appear as author' + assert_equal 6, result.authors.size + end end + test 'model and datafile association' do publication = FactoryBot.create(:publication) diff --git a/test/vcr_cassettes/doi/crossref_ra.yml b/test/vcr_cassettes/doi/crossref_ra.yml new file mode 100644 index 0000000000..e58dedd2f1 --- /dev/null +++ b/test/vcr_cassettes/doi/crossref_ra.yml @@ -0,0 +1,58 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1038/s41586-020-2649-2 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 12:20:09 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=HcUhfJCHAFWq7S0iCcwb0XOFpgEvKgcFzJT9ddCKgkPUEoNKnaIfxaMnTBuBhbjCVu2DY%2BbNOSbkpXskYjWvGecslyyjNXJ%2BdnNsDxgvWD%2F00Q%3D%3D"}]}' + Cf-Ray: + - 996add769a50d37a-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1038/s41586-020-2649-2", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 12:20:09 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/datacite_ra.yml b/test/vcr_cassettes/doi/datacite_ra.yml new file mode 100644 index 0000000000..83d8215242 --- /dev/null +++ b/test/vcr_cassettes/doi/datacite_ra.yml @@ -0,0 +1,58 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.5281/zenodo.16736322 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 12:12:51 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=IpZProTDqskAmdbjM7dthIUMvovdkV00pPo9mo55fDkaqLJH08J5hLkHJ%2BB9Ni6T6jjSd%2FtzYIbNnGXcoFR69FtF4YAoXwoF%2BDx%2BcgQypZdKiQ%3D%3D"}]}' + Cf-Ray: + - 996ad2c3586e65c2-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.5281/zenodo.16736322", + "RA": "DataCite" + } + ] + recorded_at: Thu, 30 Oct 2025 12:12:51 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_1.yml b/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_1.yml new file mode 100644 index 0000000000..e1be73698c --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_1.yml @@ -0,0 +1,142 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1007/978-3-642-16239-8_8 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:26 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=N34OCLSkI7h1G7jtnwR4578GFksOVyhZ5Ojtj%2BgHFbWYsJab5pOcZ67gVgDyU2MOyYjEhzeYy1eBUQYVxHVnyyfp6rboTtnuaTuzfNryQkKSlQ%3D%3D"}]}' + Cf-Ray: + - 996d9725ac265cda-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1007/978-3-642-16239-8_8", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:26 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1007/978-3-642-16239-8_8 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:27 GMT + Content-Type: + - application/json + Content-Length: + - '4776' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2025,10,30]],"date-time":"2025-10-30T17:06:51Z","timestamp":1761844011885},"publisher-location":"Berlin, + Heidelberg","reference-count":10,"publisher":"Springer Berlin Heidelberg","isbn-type":[{"type":"print","value":"9783642162381"},{"type":"electronic","value":"9783642162398"}],"content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"published-print":{"date-parts":[[2010]]},"DOI":"10.1007\/978-3-642-16239-8_8","type":"book-chapter","created":{"date-parts":[[2010,9,30]],"date-time":"2010-09-30T23:14:43Z","timestamp":1285888483000},"page":"37-44","source":"Crossref","is-referenced-by-count":48,"title":["Prediction + with Confidence Based on a Random Forest Classifier"],"prefix":"10.1007","author":[{"given":"Dmitry","family":"Devetyarov","sequence":"first","affiliation":[]},{"given":"Ilia","family":"Nouretdinov","sequence":"additional","affiliation":[]}],"member":"297","reference":[{"key":"8_CR1","volume-title":"Algorithmic + Learning in a Random World","author":"V. Vovk","year":"2005","unstructured":"Vovk, + V., Gammerman, A., Shafer, G.: Algorithmic Learning in a Random World. Springer, + New York (2005)"},{"key":"8_CR2","unstructured":"Gammerman, A., Vovk, V., + Vapnik, V.: Learning by Transduction. In: 14th Conference on Uncertainty in + Artificial Intelligence, pp. 148\u2013155 (1998)"},{"key":"8_CR3","doi-asserted-by":"crossref","unstructured":"Proedrou, + K., Nouretdinov, I., Vovk, V., Gammerman, A.: Transductive Confidence Machines + for Pattern Recognition. Technical report 01-02, Royal Holloway, University + of London (2001)","DOI":"10.1007\/3-540-36755-1_32"},{"key":"8_CR4","doi-asserted-by":"publisher","first-page":"5","DOI":"10.1023\/A:1010933404324","volume":"45","author":"L. + Breiman","year":"2001","unstructured":"Breiman, L.: Random Forests. Mach. + Learn.\u00a045, 5\u201332 (2001)","journal-title":"Mach. Learn."},{"key":"8_CR5","unstructured":"Breiman, + L., Cutler, A.: Random Forests, http:\/\/www.stat.berkeley.edu\/users\/breiman\/RandomForests\/cc_home.htm#intro"},{"key":"8_CR6","doi-asserted-by":"publisher","first-page":"262","DOI":"10.1373\/clinchem.2009.133363","volume":"56","author":"J.F. + Timms","year":"2010","unstructured":"Timms, J.F., Cramer, R., Camuzeaux, S., + Tiss, A., Smith, C., Burford, B., Nouretdinov, I., Devetyarov, D., Gentry-Maharaj, + A., Ford, J., Luo, Z., Gammerman, A., Menon, U., Jacobs, I.: Peptides Generated + Ex Vivo from Abundant Serum Proteins by Tumour-Specific Txopeptidases are + Not Useful Biomarkers in Ovarian Cancer. Clin. Chem.\u00a056, 262\u2013271 + (2010)","journal-title":"Clin. Chem."},{"key":"8_CR7","doi-asserted-by":"crossref","unstructured":"Gammerman, + A., Nouretdinov, I., Burford, B., Chervonenkis, A., Vovk, V., Luo, Z.: Clinical + Mass Spectrometry Proteomic Diagnosis by Conformal Predictors. Stat. Appl. + Genet. Mo. B.\u00a07(2), Art.\u00a013 (2008)","DOI":"10.2202\/1544-6115.1385"},{"key":"8_CR8","unstructured":"Nouretdinov, + I., Burford, B., Luo, Z., Gammerman, A.: Data Analysis of 7 Biomarkers. Technical + report, Royal Holloway, University of London (2008)"},{"issue":"1","key":"8_CR9","doi-asserted-by":"crossref","first-page":"15","DOI":"10.1055\/s-0038-1634813","volume":"30","author":"A. + Gammerman","year":"1991","unstructured":"Gammerman, A., Thatcher, A.R.: Bayesian + Diagnostic Probabilities without Assuming Independence of Symptoms. Method + Inform Med.\u00a030(1), 15\u201322 (1991)","journal-title":"Method Inform + Med."},{"key":"8_CR10","doi-asserted-by":"crossref","unstructured":"Nouretdinov, + I., Burford, B., Gammerman, A.: Application of Inductive Confidence Machine + to ICMLA Competition Data. In: The Eighth International Conference on Machine + Learning and Applications, pp. 435\u2013438 (2009)","DOI":"10.1109\/ICMLA.2009.24"}],"container-title":["IFIP + Advances in Information and Communication Technology","Artificial Intelligence + Applications and Innovations"],"original-title":[],"link":[{"URL":"http:\/\/link.springer.com\/content\/pdf\/10.1007\/978-3-642-16239-8_8.pdf","content-type":"unspecified","content-version":"vor","intended-application":"similarity-checking"}],"deposited":{"date-parts":[[2020,11,23]],"date-time":"2020-11-23T21:46:30Z","timestamp":1606167990000},"score":1,"resource":{"primary":{"URL":"http:\/\/link.springer.com\/10.1007\/978-3-642-16239-8_8"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2010]]},"ISBN":["9783642162381","9783642162398"],"references-count":10,"URL":"https:\/\/doi.org\/10.1007\/978-3-642-16239-8_8","relation":{},"ISSN":["1868-4238","1861-2288"],"issn-type":[{"type":"print","value":"1868-4238"},{"type":"electronic","value":"1861-2288"}],"subject":[],"published":{"date-parts":[[2010]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:27 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_2.yml b/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_2.yml new file mode 100644 index 0000000000..4236754b70 --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_2.yml @@ -0,0 +1,153 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1007/978-3-540-70504-8_9 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:27 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=njUCrBNcSXVSCRSIkxPDpu3qGyMX6%2FvyBhuNGPhBndYOfQ0Zol64Z3XKiuCsBSPNF0qv8Vgpe4rHPxOhRIiwT5%2BeXTx9qs4uic%2FKEXh3dItJYg%3D%3D"}]}' + Cf-Ray: + - 996d972ac9279f1d-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1007/978-3-540-70504-8_9", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:27 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1007/978-3-540-70504-8_9 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:27 GMT + Content-Type: + - application/json + Content-Length: + - '6149' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2024,9,5]],"date-time":"2024-09-05T06:09:47Z","timestamp":1725516587929},"publisher-location":"Berlin, + Heidelberg","reference-count":14,"publisher":"Springer Berlin Heidelberg","isbn-type":[{"type":"print","value":"9783540705031"},{"type":"electronic","value":"9783540705048"}],"content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"DOI":"10.1007\/978-3-540-70504-8_9","type":"book-chapter","created":{"date-parts":[[2008,8,12]],"date-time":"2008-08-12T16:07:43Z","timestamp":1218557263000},"page":"87-99","source":"Crossref","is-referenced-by-count":15,"title":["A + Semantics for a Query Language over Sensors, Streams and Relations"],"prefix":"10.1007","author":[{"given":"Christian + Y. A.","family":"Brenninkmeijer","sequence":"first","affiliation":[]},{"given":"Ixent","family":"Galpin","sequence":"additional","affiliation":[]},{"given":"Alvaro + A. A.","family":"Fernandes","sequence":"additional","affiliation":[]},{"given":"Norman + W.","family":"Paton","sequence":"additional","affiliation":[]}],"member":"297","reference":[{"issue":"2","key":"9_CR1","doi-asserted-by":"publisher","first-page":"120","DOI":"10.1007\/s00778-003-0095-z","volume":"12","author":"D.J. + Abadi","year":"2003","unstructured":"Abadi, D.J., Carney, D., \u00c7etintemel, + U., Cherniack, M., et al.: Aurora: A new Model and Architecture for Data Stream + Management. VLDB J.\u00a012(2), 120\u2013139 (2003)","journal-title":"VLDB + J."},{"issue":"2","key":"9_CR2","doi-asserted-by":"publisher","first-page":"121","DOI":"10.1007\/s00778-004-0147-z","volume":"15","author":"A. + Arasu","year":"2006","unstructured":"Arasu, A., Babu, S., Widom, J.: The CQL + continuous query language: semantic foundations and query execution. VLDB + J\u00a015(2), 121\u2013142 (2006)","journal-title":"VLDB J"},{"issue":"3","key":"9_CR3","doi-asserted-by":"publisher","first-page":"6","DOI":"10.1145\/1031570.1031572","volume":"33","author":"A. + Arasu","year":"2004","unstructured":"Arasu, A., Widom, J.: A Denotational + Semantics for Continuous Queries over Streams and Relations. SIGMOD Record\u00a033(3), + 6\u201312 (2004)","journal-title":"SIGMOD Record"},{"key":"9_CR4","doi-asserted-by":"crossref","unstructured":"Babcock, + B., Babu, S., Datar, M., Motwani, R., Widom, J.: Models and Issues in Data + Stream Systems. In: PODS, pp. 1\u201316 (2002)","DOI":"10.1145\/543613.543615"},{"key":"9_CR5","doi-asserted-by":"crossref","unstructured":"Chandrasekaran, + S., Cooper, O., Deshpande, A., Franklin, M.J., et al.: TelegraphCQ: Continuous + Dataflow Processing for an Uncertain World. In: CIDR (2003)","DOI":"10.1145\/872757.872857"},{"key":"9_CR6","doi-asserted-by":"crossref","unstructured":"Chen, + J., DeWitt, D.J., Tian, F., Wang, Y.: NiagaraCQ: A Scalable Continuous Query + System for Internet Databases. In: SIGMOD, pp. 379\u2013390 (2000)","DOI":"10.1145\/342009.335432"},{"key":"9_CR7","doi-asserted-by":"crossref","unstructured":"Cranor, + C.D., Johnson, T., Spatscheck, O., Shkapenyuk, V.: Gigascope: A Stream Database + for Network Applications. In: SIGMOD, pp. 647\u2013651 (2003)","DOI":"10.1145\/872757.872838"},{"key":"9_CR8","doi-asserted-by":"crossref","unstructured":"Galpin, + I., Brenninkmeijer, C.Y.A., Jabeen, F., Fernandes, A.A.A., Paton, N.W.: An + Architecture for Query Optimization in Sensor Networks. In: Proc. ICDE (2008)","DOI":"10.1109\/ICDE.2008.4497582"},{"issue":"2","key":"9_CR9","doi-asserted-by":"publisher","first-page":"5","DOI":"10.1145\/776985.776986","volume":"32","author":"L. + Golab","year":"2003","unstructured":"Golab, L., \u00d6zsu, M.T.: Issues in + data stream management. SIGMOD Record\u00a032(2), 5\u201314 (2003)","journal-title":"SIGMOD + Record"},{"issue":"1","key":"9_CR10","doi-asserted-by":"publisher","first-page":"122","DOI":"10.1145\/1061318.1061322","volume":"30","author":"S. + Madden","year":"2005","unstructured":"Madden, S., Franklin, M.J., Hellerstein, + J.M., Hong, W.: TinyDB: An Acquisitional Query Processing System for Sensor + Networks. ACM Trans. Database Syst.\u00a030(1), 122\u2013173 (2005)","journal-title":"ACM + Trans. Database Syst."},{"key":"9_CR11","series-title":"Lecture Notes in Computer + Science","doi-asserted-by":"crossref","first-page":"37","DOI":"10.1007\/978-3-540-30570-5_3","volume-title":"Database + Theory - ICDT 2005","author":"D. Maier","year":"2004","unstructured":"Maier, + D., Li, J., Tucker, P.A., Tufte, K., Papadimos, V.: Semantics of Data Streams + and Operators. In: Eiter, T., Libkin, L. (eds.) ICDT 2005. LNCS, vol.\u00a03363, + pp. 37\u201352. Springer, Heidelberg (2004)"},{"key":"9_CR12","volume-title":"StreamDataManagement, + ch. 3","author":"D. Maier","year":"2005","unstructured":"Maier, D., Tucker, + P.A., Garofalakis, M.: Filtering, Punctuation, Windows and Synopses. In: Chaudhury, + N.A., et al. (eds.) StreamDataManagement, ch. 3, Springer, Heidelberg (2005)"},{"key":"9_CR13","doi-asserted-by":"crossref","unstructured":"Rundensteiner, + E.A., Ding, L., Sutherland, T.M., Zhu, Y., et al.: CAPE: Continuous Query + Engine with Heterogeneous-Grained Adaptivity. In: VLDB (2004)","DOI":"10.1016\/B978-012088469-8\/50145-5"},{"key":"9_CR14","unstructured":"Yao, + Y., Gehrke, J.: Query Processing in Sensor Networks. In: CIDR (2003)"}],"container-title":["Lecture + Notes in Computer Science","Sharing Data, Information and Knowledge"],"original-title":[],"language":"en","link":[{"URL":"http:\/\/link.springer.com\/content\/pdf\/10.1007\/978-3-540-70504-8_9.pdf","content-type":"unspecified","content-version":"vor","intended-application":"similarity-checking"}],"deposited":{"date-parts":[[2020,11,19]],"date-time":"2020-11-19T05:06:52Z","timestamp":1605762412000},"score":1,"resource":{"primary":{"URL":"http:\/\/link.springer.com\/10.1007\/978-3-540-70504-8_9"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[null]]},"ISBN":["9783540705031","9783540705048"],"references-count":14,"URL":"https:\/\/doi.org\/10.1007\/978-3-540-70504-8_9","relation":{},"ISSN":["0302-9743","1611-3349"],"issn-type":[{"type":"print","value":"0302-9743"},{"type":"electronic","value":"1611-3349"}],"subject":[]}}' + recorded_at: Thu, 30 Oct 2025 20:16:27 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_3.yml b/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_3.yml new file mode 100644 index 0000000000..5d9a8b7b71 --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_book_chapter_response_3.yml @@ -0,0 +1,142 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1007/978-3-642-16239-8_8 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:28 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=1foGqJnvuaGb9AEf%2Bry1fxS5Q%2FzCIpcbnkRNrVna%2BxaTLpeU96yHoYaNwgtRoYH%2FfmBxMTL4h8e6keldjQTsAtzeaH%2FLKNjALFUUI3cngSybYA%3D%3D"}]}' + Cf-Ray: + - 996d972f5d69dbda-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1007/978-3-642-16239-8_8", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:28 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1007/978-3-642-16239-8_8 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:28 GMT + Content-Type: + - application/json + Content-Length: + - '4776' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2025,10,30]],"date-time":"2025-10-30T17:06:51Z","timestamp":1761844011885},"publisher-location":"Berlin, + Heidelberg","reference-count":10,"publisher":"Springer Berlin Heidelberg","isbn-type":[{"type":"print","value":"9783642162381"},{"type":"electronic","value":"9783642162398"}],"content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"published-print":{"date-parts":[[2010]]},"DOI":"10.1007\/978-3-642-16239-8_8","type":"book-chapter","created":{"date-parts":[[2010,9,30]],"date-time":"2010-09-30T23:14:43Z","timestamp":1285888483000},"page":"37-44","source":"Crossref","is-referenced-by-count":48,"title":["Prediction + with Confidence Based on a Random Forest Classifier"],"prefix":"10.1007","author":[{"given":"Dmitry","family":"Devetyarov","sequence":"first","affiliation":[]},{"given":"Ilia","family":"Nouretdinov","sequence":"additional","affiliation":[]}],"member":"297","reference":[{"key":"8_CR1","volume-title":"Algorithmic + Learning in a Random World","author":"V. Vovk","year":"2005","unstructured":"Vovk, + V., Gammerman, A., Shafer, G.: Algorithmic Learning in a Random World. Springer, + New York (2005)"},{"key":"8_CR2","unstructured":"Gammerman, A., Vovk, V., + Vapnik, V.: Learning by Transduction. In: 14th Conference on Uncertainty in + Artificial Intelligence, pp. 148\u2013155 (1998)"},{"key":"8_CR3","doi-asserted-by":"crossref","unstructured":"Proedrou, + K., Nouretdinov, I., Vovk, V., Gammerman, A.: Transductive Confidence Machines + for Pattern Recognition. Technical report 01-02, Royal Holloway, University + of London (2001)","DOI":"10.1007\/3-540-36755-1_32"},{"key":"8_CR4","doi-asserted-by":"publisher","first-page":"5","DOI":"10.1023\/A:1010933404324","volume":"45","author":"L. + Breiman","year":"2001","unstructured":"Breiman, L.: Random Forests. Mach. + Learn.\u00a045, 5\u201332 (2001)","journal-title":"Mach. Learn."},{"key":"8_CR5","unstructured":"Breiman, + L., Cutler, A.: Random Forests, http:\/\/www.stat.berkeley.edu\/users\/breiman\/RandomForests\/cc_home.htm#intro"},{"key":"8_CR6","doi-asserted-by":"publisher","first-page":"262","DOI":"10.1373\/clinchem.2009.133363","volume":"56","author":"J.F. + Timms","year":"2010","unstructured":"Timms, J.F., Cramer, R., Camuzeaux, S., + Tiss, A., Smith, C., Burford, B., Nouretdinov, I., Devetyarov, D., Gentry-Maharaj, + A., Ford, J., Luo, Z., Gammerman, A., Menon, U., Jacobs, I.: Peptides Generated + Ex Vivo from Abundant Serum Proteins by Tumour-Specific Txopeptidases are + Not Useful Biomarkers in Ovarian Cancer. Clin. Chem.\u00a056, 262\u2013271 + (2010)","journal-title":"Clin. Chem."},{"key":"8_CR7","doi-asserted-by":"crossref","unstructured":"Gammerman, + A., Nouretdinov, I., Burford, B., Chervonenkis, A., Vovk, V., Luo, Z.: Clinical + Mass Spectrometry Proteomic Diagnosis by Conformal Predictors. Stat. Appl. + Genet. Mo. B.\u00a07(2), Art.\u00a013 (2008)","DOI":"10.2202\/1544-6115.1385"},{"key":"8_CR8","unstructured":"Nouretdinov, + I., Burford, B., Luo, Z., Gammerman, A.: Data Analysis of 7 Biomarkers. Technical + report, Royal Holloway, University of London (2008)"},{"issue":"1","key":"8_CR9","doi-asserted-by":"crossref","first-page":"15","DOI":"10.1055\/s-0038-1634813","volume":"30","author":"A. + Gammerman","year":"1991","unstructured":"Gammerman, A., Thatcher, A.R.: Bayesian + Diagnostic Probabilities without Assuming Independence of Symptoms. Method + Inform Med.\u00a030(1), 15\u201322 (1991)","journal-title":"Method Inform + Med."},{"key":"8_CR10","doi-asserted-by":"crossref","unstructured":"Nouretdinov, + I., Burford, B., Gammerman, A.: Application of Inductive Confidence Machine + to ICMLA Competition Data. In: The Eighth International Conference on Machine + Learning and Applications, pp. 435\u2013438 (2009)","DOI":"10.1109\/ICMLA.2009.24"}],"container-title":["IFIP + Advances in Information and Communication Technology","Artificial Intelligence + Applications and Innovations"],"original-title":[],"link":[{"URL":"http:\/\/link.springer.com\/content\/pdf\/10.1007\/978-3-642-16239-8_8.pdf","content-type":"unspecified","content-version":"vor","intended-application":"similarity-checking"}],"deposited":{"date-parts":[[2020,11,23]],"date-time":"2020-11-23T21:46:30Z","timestamp":1606167990000},"score":1,"resource":{"primary":{"URL":"http:\/\/link.springer.com\/10.1007\/978-3-642-16239-8_8"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2010]]},"ISBN":["9783642162381","9783642162398"],"references-count":10,"URL":"https:\/\/doi.org\/10.1007\/978-3-642-16239-8_8","relation":{},"ISSN":["1868-4238","1861-2288"],"issn-type":[{"type":"print","value":"1868-4238"},{"type":"electronic","value":"1861-2288"}],"subject":[],"published":{"date-parts":[[2010]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:28 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_book_response_1.yml b/test/vcr_cassettes/doi/doi_crossref_book_response_1.yml new file mode 100644 index 0000000000..056a824e28 --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_book_response_1.yml @@ -0,0 +1,126 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.23943/princeton/9780691161914.003.0002 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:25 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=F7CyQqkbQqak0LnO055XEAuHaYsxTFr%2FQsJlrknsDov%2BP3345aT1mN63ilC%2FkzPuc9mZLMI7X1ZaNNf662EkxHmalYMgbBhmtgKXDWbEs%2Brjsw%3D%3D"}]}' + Cf-Ray: + - 996d971c4f6595b3-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.23943/princeton/9780691161914.003.0002", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:25 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.23943/princeton/9780691161914.003.0002 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:25 GMT + Content-Type: + - application/json + Content-Length: + - '2360' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2022,7,29]],"date-time":"2022-07-29T04:19:31Z","timestamp":1659068371433},"reference-count":0,"publisher":"Princeton + University Press","content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"published-print":{"date-parts":[[2017,10,19]]},"abstract":"

This + chapter shows how book 1 of Paradise Lost<\/italic> metaphorically + depicts the role of the devil in raising the rebel angels out of their \u201cbottomless + perdition,\u201d an act of poetic creation analogous to the divine creation + of the universe described in the invocation\u2014\u201chow the heavens and + earth\/Rose out of chaos.\u201d The chief devils described in the catalog + that occupies the center of book 1 and organizes its poetic figures and symbolic + geography\u2014Carthage, Sodom, Egypt, Babel-Babylon, Rome\u2014are precisely + those who will come to inhabit the pagan shrines that human idolatry will + build next to or even inside the Jerusalem temple, profaning God''s house. + This catalog\u2014whose traditional epic function is to size up military force\u2014instead + suggests the force of spiritual falsehood, and it corresponds to the defeated + devils'' own reluctance to pursue another direct war against God; they would + rather resort to satanic fraud.<\/p>","DOI":"10.23943\/princeton\/9780691161914.003.0002","type":"book","created":{"date-parts":[[2017,11,21]],"date-time":"2017-11-21T13:37:09Z","timestamp":1511271429000},"source":"Crossref","is-referenced-by-count":0,"title":["Milton\u2019s + Book of Numbers: Book 1 and Its Catalog"],"prefix":"10.23943","author":[{"given":"David","family":"Quint","sequence":"first","affiliation":[]}],"member":"10341","container-title":["Princeton + University Press"],"original-title":["Milton\u2019s Book of Numbers: Book + 1 and Its Catalog"],"deposited":{"date-parts":[[2022,7,28]],"date-time":"2022-07-28T14:40:42Z","timestamp":1659019242000},"score":1,"resource":{"primary":{"URL":"https:\/\/academic.oup.com\/princeton-scholarship-online\/book\/16275\/chapter\/171374633"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2017,10,19]]},"references-count":0,"URL":"https:\/\/doi.org\/10.23943\/princeton\/9780691161914.003.0002","relation":{},"subject":[],"published":{"date-parts":[[2017,10,19]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:25 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_book_response_2.yml b/test/vcr_cassettes/doi/doi_crossref_book_response_2.yml new file mode 100644 index 0000000000..862b0c5783 --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_book_response_2.yml @@ -0,0 +1,114 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1007/978-3-540-70504-8 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:25 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=uNE3vHfW0siUn706bEUp7CRkjJtHHEDCaIz60jW%2FrOs5M98rWFBiaiAkN6DInSHztjDxCoWCJMwvON5R41MVv37kW5LUrHv%2FDAX8DxkpKjpzOg%3D%3D"}]}' + Cf-Ray: + - 996d9720ddaa4d2b-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1007/978-3-540-70504-8", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:25 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1007/978-3-540-70504-8 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:26 GMT + Content-Type: + - application/json + Content-Length: + - '2343' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2025,5,15]],"date-time":"2025-05-15T02:47:42Z","timestamp":1747277262358},"publisher-location":"Berlin, + Heidelberg","reference-count":0,"publisher":"Springer Berlin Heidelberg","isbn-type":[{"type":"print","value":"9783540705031"},{"type":"electronic","value":"9783540705048"}],"license":[{"start":{"date-parts":[[2008,1,1]],"date-time":"2008-01-01T00:00:00Z","timestamp":1199145600000},"content-version":"tdm","delay-in-days":0,"URL":"http:\/\/www.springer.com\/tdm"}],"content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"published-print":{"date-parts":[[2008]]},"DOI":"10.1007\/978-3-540-70504-8","type":"book","created":{"date-parts":[[2008,8,12]],"date-time":"2008-08-12T12:07:43Z","timestamp":1218542863000},"source":"Crossref","is-referenced-by-count":6,"title":["Sharing + Data, Information and Knowledge"],"prefix":"10.1007","member":"297","container-title":["Lecture + Notes in Computer Science"],"original-title":[],"language":"en","link":[{"URL":"http:\/\/link.springer.com\/content\/pdf\/10.1007\/978-3-540-70504-8.pdf","content-type":"application\/pdf","content-version":"vor","intended-application":"text-mining"},{"URL":"http:\/\/link.springer.com\/content\/pdf\/10.1007\/978-3-540-70504-8","content-type":"unspecified","content-version":"vor","intended-application":"similarity-checking"}],"deposited":{"date-parts":[[2019,5,19]],"date-time":"2019-05-19T11:45:50Z","timestamp":1558266350000},"score":1,"resource":{"primary":{"URL":"http:\/\/link.springer.com\/10.1007\/978-3-540-70504-8"}},"subtitle":["25th + British National Conference on Databases, BNCOD 25, Cardiff, UK, July 7-10, + 2008. Proceedings"],"editor":[{"given":"Alex","family":"Gray","sequence":"first","affiliation":[]},{"given":"Keith","family":"Jeffery","sequence":"additional","affiliation":[]},{"given":"Jianhua","family":"Shao","sequence":"additional","affiliation":[]}],"short-title":[],"issued":{"date-parts":[[2008]]},"ISBN":["9783540705031","9783540705048"],"references-count":0,"URL":"https:\/\/doi.org\/10.1007\/978-3-540-70504-8","relation":{},"ISSN":["0302-9743","1611-3349"],"issn-type":[{"type":"print","value":"0302-9743"},{"type":"electronic","value":"1611-3349"}],"subject":[],"published":{"date-parts":[[2008]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:26 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_book_with_editor_subtitle_response.yml b/test/vcr_cassettes/doi/doi_crossref_book_with_editor_subtitle_response.yml new file mode 100644 index 0000000000..ddd6e97186 --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_book_with_editor_subtitle_response.yml @@ -0,0 +1,112 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.2307/j.ctvn5txvs + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:38 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=NP86kdAOBcjGqOjBvJih2CrRawIXSyl8NPK%2FJZRKFoLAuDPWSrjRtCE6owr0huJpaQQ6BMaiH5tRR8lMBcsAjaFesSmmnsaDYn%2BlzFBOOwwjDQ%3D%3D"}]}' + Cf-Ray: + - 996d97731b4e4d37-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.2307/j.ctvn5txvs", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:38 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.2307/j.ctvn5txvs + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:40 GMT + Content-Type: + - application/json + Content-Length: + - '1455' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2025,7,8]],"date-time":"2025-07-08T05:46:48Z","timestamp":1751953608465},"reference-count":0,"publisher":"Medieval + Institute Publications","isbn-type":[{"value":"9781580443982","type":"electronic"},{"value":"1580443982","type":"electronic"},{"value":"9781879288997","type":"print"}],"content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"published-print":{"date-parts":[[1998,3,1]]},"DOI":"10.2307\/j.ctvn5txvs","type":"monograph","created":{"date-parts":[[2019,8,14]],"date-time":"2019-08-14T16:29:17Z","timestamp":1565800157000},"source":"Crossref","is-referenced-by-count":7,"title":["Troy + Book"],"prefix":"10.2307","author":[{"given":"John","family":"Lydgate","sequence":"first","affiliation":[]}],"member":"1121","container-title":[],"original-title":[],"deposited":{"date-parts":[[2019,8,14]],"date-time":"2019-08-14T16:29:17Z","timestamp":1565800157000},"score":1,"resource":{"primary":{"URL":"http:\/\/www.jstor.org\/stable\/10.2307\/j.ctvn5txvs"}},"subtitle":["Selections"],"editor":[{"given":"Robert + R.","family":"Edwards","sequence":"additional","affiliation":[]}],"short-title":[],"issued":{"date-parts":[[1998,3,1]]},"ISBN":["9781580443982","1580443982","9781879288997"],"references-count":0,"URL":"https:\/\/doi.org\/10.2307\/j.ctvn5txvs","relation":{},"subject":[],"published":{"date-parts":[[1998,3,1]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:40 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_journal_article_response_1.yml b/test/vcr_cassettes/doi/doi_crossref_journal_article_response_1.yml new file mode 100644 index 0000000000..e7a274a1db --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_journal_article_response_1.yml @@ -0,0 +1,308 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1038/s41586-020-2649-2 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:29 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=qb%2Fdk9E0gJbOc7%2FTv63y903BXNulYwnLcE4YFEDYjRKSmRDqwjKrwcGhsiEuDHbMOfNMKsMYFj9TjhjVjKJUrFZwWTTQeRQrnQz8zT9B8jTEOQ%3D%3D"}]}' + Cf-Ray: + - 996d9737d8775d45-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1038/s41586-020-2649-2", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:29 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1038/s41586-020-2649-2 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:29 GMT + Content-Type: + - application/json + Content-Length: + - '24627' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2025,10,30]],"date-time":"2025-10-30T17:27:49Z","timestamp":1761845269596,"version":"3.41.0"},"reference-count":57,"publisher":"Springer + Science and Business Media LLC","issue":"7825","license":[{"start":{"date-parts":[[2020,9,16]],"date-time":"2020-09-16T00:00:00Z","timestamp":1600214400000},"content-version":"tdm","delay-in-days":0,"URL":"https:\/\/creativecommons.org\/licenses\/by\/4.0"},{"start":{"date-parts":[[2020,9,16]],"date-time":"2020-09-16T00:00:00Z","timestamp":1600214400000},"content-version":"vor","delay-in-days":0,"URL":"https:\/\/creativecommons.org\/licenses\/by\/4.0"}],"content-domain":{"domain":["link.springer.com"],"crossmark-restriction":false},"short-container-title":["Nature"],"published-print":{"date-parts":[[2020,9,17]]},"abstract":"Abstract<\/jats:title>Array + programming provides a powerful, compact and expressive syntax for accessing, + manipulating and operating on data in vectors, matrices and higher-dimensional + arrays. NumPy is the primary array programming library for the Python language. + It has an essential role in research analysis pipelines in fields as diverse + as physics, chemistry, astronomy, geoscience, biology, psychology, materials + science, engineering, finance and economics. For example, in astronomy, NumPy + was an important part of the software stack used in the discovery of gravitational + waves1<\/jats:sup>and in the first imaging of a black hole2<\/jats:sup>. + Here we review how a few fundamental array concepts lead to a simple and powerful + programming paradigm for organizing, exploring and analysing scientific data. + NumPy is the foundation upon which the scientific Python ecosystem is constructed. + It is so pervasive that several projects, targeting audiences with specialized + needs, have developed their own NumPy-like interfaces and array objects. Owing + to its central position in the ecosystem, NumPy increasingly acts as an interoperability + layer between such array computation libraries and, together with its application + programming interface (API), provides a flexible framework to support the + next decade of scientific and industrial analysis.<\/jats:p>","DOI":"10.1038\/s41586-020-2649-2","type":"journal-article","created":{"date-parts":[[2020,9,17]],"date-time":"2020-09-17T20:48:17Z","timestamp":1600375697000},"page":"357-362","update-policy":"https:\/\/doi.org\/10.1007\/springer_crossmark_policy","source":"Crossref","is-referenced-by-count":18149,"title":["Array + programming with NumPy"],"prefix":"10.1038","volume":"585","author":[{"given":"Charles + R.","family":"Harris","sequence":"first","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0002-5263-5070","authenticated-orcid":false,"given":"K. + Jarrod","family":"Millman","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0001-9276-1891","authenticated-orcid":false,"given":"St\u00e9fan + J.","family":"van der Walt","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0002-0300-3333","authenticated-orcid":false,"given":"Ralf","family":"Gommers","sequence":"additional","affiliation":[]},{"given":"Pauli","family":"Virtanen","sequence":"additional","affiliation":[]},{"given":"David","family":"Cournapeau","sequence":"additional","affiliation":[]},{"given":"Eric","family":"Wieser","sequence":"additional","affiliation":[]},{"given":"Julian","family":"Taylor","sequence":"additional","affiliation":[]},{"given":"Sebastian","family":"Berg","sequence":"additional","affiliation":[]},{"given":"Nathaniel + J.","family":"Smith","sequence":"additional","affiliation":[]},{"given":"Robert","family":"Kern","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0002-1771-9949","authenticated-orcid":false,"given":"Matti","family":"Picus","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0002-5207-0380","authenticated-orcid":false,"given":"Stephan","family":"Hoyer","sequence":"additional","affiliation":[]},{"given":"Marten + H.","family":"van Kerkwijk","sequence":"additional","affiliation":[]},{"given":"Matthew","family":"Brett","sequence":"additional","affiliation":[]},{"given":"Allan","family":"Haldane","sequence":"additional","affiliation":[]},{"given":"Jaime + Fern\u00e1ndez","family":"del R\u00edo","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0003-3603-8038","authenticated-orcid":false,"given":"Mark","family":"Wiebe","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0001-7328-4305","authenticated-orcid":false,"given":"Pearu","family":"Peterson","sequence":"additional","affiliation":[]},{"given":"Pierre","family":"G\u00e9rard-Marchant","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0001-8700-2292","authenticated-orcid":false,"given":"Kevin","family":"Sheppard","sequence":"additional","affiliation":[]},{"given":"Tyler","family":"Reddy","sequence":"additional","affiliation":[]},{"given":"Warren","family":"Weckesser","sequence":"additional","affiliation":[]},{"given":"Hameer","family":"Abbasi","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0001-8108-7707","authenticated-orcid":false,"given":"Christoph","family":"Gohlke","sequence":"additional","affiliation":[]},{"given":"Travis + E.","family":"Oliphant","sequence":"additional","affiliation":[]}],"member":"297","published-online":{"date-parts":[[2020,9,16]]},"reference":[{"key":"2649_CR1","doi-asserted-by":"publisher","first-page":"061102","DOI":"10.1103\/PhysRevLett.116.061102","volume":"116","author":"BP + Abbott","year":"2016","unstructured":"Abbott, B. P. et al. Observation of + gravitational waves from a binary black hole merger. Phys. Rev. Lett. 116, + 061102 (2016).","journal-title":"Phys. Rev. Lett."},{"key":"2649_CR2","doi-asserted-by":"publisher","first-page":"11","DOI":"10.3847\/0004-637X\/829\/1\/11","volume":"286","author":"A + Chael","year":"2016","unstructured":"Chael, A. et al. High-resolution linear + polarimetric imaging for the Event Horizon Telescope. Astrophys. J. 286, 11 + (2016).","journal-title":"Astrophys. J."},{"key":"2649_CR3","doi-asserted-by":"publisher","first-page":"262","DOI":"10.1063\/1.4822400","volume":"10","author":"PF + Dubois","year":"1996","unstructured":"Dubois, P. F., Hinsen, K. & Hugunin, + J. Numerical Python. Comput. Phys. 10, 262\u2013267 (1996).","journal-title":"Comput. + Phys."},{"key":"2649_CR4","unstructured":"Ascher, D., Dubois, P. F., Hinsen, + K., Hugunin, J. & Oliphant, T. E. An Open Source Project: Numerical Python + (Lawrence Livermore National Laboratory, 2001)."},{"key":"2649_CR5","unstructured":"Yang, + T.-Y., Furnish, G. & Dubois, P. F. Steering object-oriented scientific computations. + In Proc. TOOLS USA 97. Intl Conf. Technology of Object Oriented Systems and + Languages (eds Ege,\u00a0R., Singh,\u00a0M.\u00a0& Meyer,\u00a0B.) 112\u2013119 + (IEEE, 1997)."},{"key":"2649_CR6","unstructured":"Greenfield, P., Miller, + J. T., Hsu, J. & White, R. L. numarray: a new scientific array package for + Python. In PyCon DC 2003 http:\/\/citeseerx.ist.psu.edu\/viewdoc\/download?doi=10.1.1.112.9899 + (2003)."},{"key":"2649_CR7","unstructured":"Oliphant, T. E. Guide to NumPy + 1st edn (Trelgol Publishing, 2006)."},{"key":"2649_CR8","doi-asserted-by":"publisher","first-page":"7","DOI":"10.1109\/MCSE.2007.51","volume":"9","author":"PF + Dubois","year":"2007","unstructured":"Dubois, P. F. Python: batteries included. + Comput. Sci. Eng. 9, 7\u20139 (2007).","journal-title":"Comput. Sci. Eng."},{"key":"2649_CR9","doi-asserted-by":"publisher","first-page":"10","DOI":"10.1109\/MCSE.2007.58","volume":"9","author":"TE + Oliphant","year":"2007","unstructured":"Oliphant, T. E. Python for scientific + computing. Comput. Sci. Eng. 9, 10\u201320 (2007).","journal-title":"Comput. + Sci. Eng."},{"key":"2649_CR10","doi-asserted-by":"publisher","first-page":"9","DOI":"10.1109\/MCSE.2011.36","volume":"13","author":"KJ + Millman","year":"2011","unstructured":"Millman, K. J. & Aivazis, M. Python + for scientists and engineers. Comput. Sci. Eng. 13, 9\u201312 (2011).","journal-title":"Comput. + Sci. Eng."},{"key":"2649_CR11","doi-asserted-by":"publisher","first-page":"13","DOI":"10.1109\/MCSE.2010.119","volume":"13","author":"F + P\u00e9rez","year":"2011","unstructured":"P\u00e9rez, F., Granger, B. E. & + Hunter, J. D. Python: an ecosystem for scientific computing. Comput. Sci. + Eng. 13, 13\u201321 (2011). Explains why the scientific Python ecosystem is + a highly productive environment for research.","journal-title":"Comput. Sci. + Eng."},{"key":"2649_CR12","doi-asserted-by":"publisher","first-page":"261","DOI":"10.1038\/s41592-019-0686-2","volume":"17","author":"P + Virtanen","year":"2020","unstructured":"Virtanen, P. et al. SciPy 1.0\u2014fundamental + algorithms for scientific computing in Python. Nat. Methods 17, 261\u2013272 + (2020); correction 17, 352 (2020). Introduces the SciPy library and includes + a more detailed history of NumPy and SciPy.","journal-title":"Nat. Methods"},{"key":"2649_CR13","doi-asserted-by":"publisher","first-page":"90","DOI":"10.1109\/MCSE.2007.55","volume":"9","author":"JD + Hunter","year":"2007","unstructured":"Hunter, J. D. Matplotlib: a 2D graphics + environment. Comput. Sci. Eng. 9, 90\u201395 (2007).","journal-title":"Comput. + Sci. Eng."},{"key":"2649_CR14","doi-asserted-by":"crossref","unstructured":"McKinney, + W. Data structures for statistical computing in Python. In Proc. 9th Python + in Science Conf. (eds van der\u00a0Walt,\u00a0S.\u00a0& Millman,\u00a0K.\u00a0J.) + 56\u201361 (2010).","DOI":"10.25080\/Majora-92bf1922-00a"},{"key":"2649_CR15","first-page":"2825","volume":"12","author":"F + Pedregosa","year":"2011","unstructured":"Pedregosa, F. et al. Scikit-learn: + machine learning in Python. J. Mach. Learn. Res. 12, 2825\u20132830 (2011).","journal-title":"J. + Mach. Learn. Res."},{"key":"2649_CR16","doi-asserted-by":"publisher","first-page":"e453","DOI":"10.7717\/peerj.453","volume":"2","author":"S + van der Walt","year":"2014","unstructured":"van der Walt, S. et al. scikit-image: + image processing in Python. PeerJ 2, e453 (2014).","journal-title":"PeerJ"},{"key":"2649_CR17","doi-asserted-by":"crossref","unstructured":"van + der Walt, S., Colbert, S. C. & Varoquaux, G. The NumPy array: a structure + for efficient numerical computation. Comput. Sci. Eng. 13, 22\u201330 (2011). + Discusses the NumPy array data structure with a focus on how it enables efficient + computation.","DOI":"10.1109\/MCSE.2011.37"},{"key":"2649_CR18","doi-asserted-by":"crossref","unstructured":"Wang, + Q., Zhang, X., Zhang, Y. & Yi, Q. AUGEM: automatically generate high performance + dense linear algebra kernels on x86 CPUs. In SC\u201913: Proc. Intl Conf. + High Performance Computing, Networking, Storage and Analysis 25 (IEEE, 2013).","DOI":"10.1145\/2503210.2503219"},{"key":"2649_CR19","doi-asserted-by":"crossref","unstructured":"Xianyi, + Z., Qian, W. & Yunquan, Z. Model-driven level 3 BLAS performance optimization + on Loongson 3A processor. In 2012 IEEE 18th Intl Conf. Parallel and Distributed + Systems 684\u2013691 (IEEE, 2012).","DOI":"10.1109\/ICPADS.2012.97"},{"key":"2649_CR20","doi-asserted-by":"publisher","first-page":"21","DOI":"10.1109\/MCSE.2007.53","volume":"9","author":"F + P\u00e9rez","year":"2007","unstructured":"P\u00e9rez, F. & Granger, B. E. + IPython: a system for interactive scientific computing. Comput. Sci. Eng. + 9, 21\u201329 (2007).","journal-title":"Comput. Sci. Eng."},{"key":"2649_CR21","unstructured":"Kluyver, + T. et al. Jupyter Notebooks\u2014a publishing format for reproducible computational + workflows. In Positioning and Power in Academic Publishing: Players, Agents + and Agendas (eds Loizides,\u00a0F.\u00a0& Schmidt,\u00a0B.) 87\u201390 (IOS + Press, 2016)."},{"key":"2649_CR22","unstructured":"Hagberg, A. A., Schult, + D. A. & Swart, P. J. Exploring network structure, dynamics, and function using + NetworkX. In Proc. 7th Python in Science Conf. (eds Varoquaux,\u00a0G., Vaught,\u00a0T.\u00a0& + Millman,\u00a0K.\u00a0J.) 11\u201315 (2008)."},{"key":"2649_CR23","doi-asserted-by":"publisher","first-page":"A33","DOI":"10.1051\/0004-6361\/201322068","volume":"558","author":"Astropy + Collaboration","year":"2013","unstructured":"Astropy Collaboration et al. + Astropy: a community Python package for astronomy. Astron. Astrophys. 558, + A33 (2013).","journal-title":"Astron. Astrophys."},{"key":"2649_CR24","doi-asserted-by":"publisher","first-page":"123","DOI":"10.3847\/1538-3881\/aac387","volume":"156","author":"AM + Price-Whelan","year":"2018","unstructured":"Price-Whelan, A. M. et al. The + Astropy Project: building an open-science project and status of the v2.0 core + package. Astron. J. 156, 123 (2018).","journal-title":"Astron. J."},{"key":"2649_CR25","doi-asserted-by":"publisher","first-page":"1422","DOI":"10.1093\/bioinformatics\/btp163","volume":"25","author":"PJ + Cock","year":"2009","unstructured":"Cock, P. J. et al. Biopython: freely available + Python tools for computational molecular biology and bioinformatics. Bioinformatics + 25, 1422\u20131423 (2009).","journal-title":"Bioinformatics"},{"key":"2649_CR26","doi-asserted-by":"publisher","first-page":"52","DOI":"10.1109\/MCSE.2007.46","volume":"9","author":"KJ + Millman","year":"2007","unstructured":"Millman, K. J. & Brett, M. Analysis + of functional magnetic resonance imaging in Python. Comput. Sci. Eng. 9, 52\u201355 + (2007).","journal-title":"Comput. Sci. Eng."},{"key":"2649_CR27","doi-asserted-by":"publisher","first-page":"014009","DOI":"10.1088\/1749-4699\/8\/1\/014009","volume":"8","author":"The + SunPy Community et al.","year":"2015","unstructured":"The SunPy Community + et al. SunPy\u2014Python for solar physics. Comput. Sci. Discov. 8, 014009 + (2015).","journal-title":"Comput. Sci. Discov."},{"key":"2649_CR28","unstructured":"Hamman, + J., Rocklin, M. & Abernathy, R. Pangeo: a big-data ecosystem for scalable + Earth system science. In EGU General Assembly Conf. Abstracts 12146 (2018)."},{"key":"2649_CR29","unstructured":"Chael, + A. A. et al. ehtim: imaging, analysis, and simulation software for radio interferometry. + Astrophysics Source Code Library https:\/\/ascl.net\/1904.004 (2019)."},{"key":"2649_CR30","doi-asserted-by":"crossref","unstructured":"Millman, + K. J. & P\u00e9rez, F. Developing open source scientific practice. In Implementing + Reproducible Research (eds Stodden,\u00a0V., Leisch,\u00a0F.\u00a0& Peng,\u00a0R.\u00a0D.) + 149\u2013183 (CRC Press, 2014). Describes the software engineering practices + embraced by the NumPy and SciPy communities with a focus on how these practices + improve research.","DOI":"10.1201\/9781315373461-6"},{"key":"2649_CR31","unstructured":"van + der Walt, S. The SciPy Documentation Project (technical overview). In Proc. + 7th Python in Science Conf. (SciPy 2008) (eds Varoquaux,\u00a0G., Vaught,\u00a0T.\u00a0& + Millman,\u00a0K.\u00a0J.) 27\u201328 (2008)."},{"key":"2649_CR32","unstructured":"Harrington, + J. The SciPy Documentation Project. In Proc. 7th Python in Science Conference + (SciPy 2008) (eds Varoquaux,\u00a0G., Vaught,\u00a0T.\u00a0& Millman, K.\u00a0J.) + 33\u201335 (2008)."},{"key":"2649_CR33","unstructured":"Harrington, J. & Goldsmith, + D. Progress report: NumPy and SciPy documentation in 2009. In Proc. 8th Python + in Science Conf. (SciPy 2009) (eds Varoquaux,\u00a0G., van der\u00a0Walt,\u00a0S.\u00a0& + Millman,\u00a0K.\u00a0J.) 84\u201387 (2009)."},{"key":"2649_CR34","unstructured":"Royal + Astronomical Society Report of the RAS \u2018A\u2019 Awards Committee 2020: + Astropy Project: 2020 Group Achievement Award (A) https:\/\/ras.ac.uk\/sites\/default\/files\/2020-01\/Group%20Award%20-%20Astropy.pdf + (2020)."},{"key":"2649_CR35","doi-asserted-by":"publisher","first-page":"66","DOI":"10.1109\/MCSE.2006.122","volume":"8","author":"G + Wilson","year":"2006","unstructured":"Wilson, G. Software carpentry: getting + scientists to write better code by making them more productive. Comput. Sci. + Eng. 8, 66\u201369 (2006).","journal-title":"Comput. Sci. Eng."},{"key":"2649_CR36","doi-asserted-by":"crossref","unstructured":"Hannay, + J. E. et al. How do scientists develop and use scientific software? In Proc. + 2009 ICSE Workshop on Software Engineering for Computational Science and Engineering + 1\u20138 (IEEE, 2009).","DOI":"10.1109\/SECSE.2009.5069155"},{"key":"2649_CR37","doi-asserted-by":"publisher","first-page":"727","DOI":"10.3389\/fnins.2018.00727","volume":"12","author":"KJ + Millman","year":"2018","unstructured":"Millman, K. J., Brett, M., Barnowski, + R. & Poline, J.-B. Teaching computational reproducibility for neuroimaging. + Front. Neurosci. 12, 727 (2018).","journal-title":"Front. Neurosci."},{"key":"2649_CR38","unstructured":"Paszke, + A. et al. Pytorch: an imperative style, high-performance deep learning library. + In Advances in Neural Information Processing Systems 32 (eds Wallach,\u00a0H.\u00a0et + al.) 8024\u20138035 (Neural Information Processing Systems, 2019)."},{"key":"2649_CR39","unstructured":"Abadi, + M. et al. TensorFlow: a system for large-scale machine learning. In OSDI\u201916: + Proc. 12th USENIX Conf. Operating Systems Design and Implementation (chairs + Keeton, K. & Roscoe, T.) 265\u2013283 (USENIX Association, 2016)."},{"key":"2649_CR40","unstructured":"Chen, + T. et al. MXNet: a flexible and efficient machine learning library for heterogeneous + distributed systems. Preprint at http:\/\/www.arxiv.org\/abs\/1512.01274 (2015)."},{"key":"2649_CR41","doi-asserted-by":"publisher","first-page":"10","DOI":"10.5334\/jors.148","volume":"5","author":"S + Hoyer","year":"2017","unstructured":"Hoyer, S. & Hamman, J. xarray: N\u2013D + labeled arrays and datasets in Python. J. Open Res. Softw. 5, 10 (2017).","journal-title":"J. + Open Res. Softw."},{"key":"2649_CR42","unstructured":"Entschev, P. Distributed + multi-GPU computing with Dask, CuPy and RAPIDS. In EuroPython 2019 https:\/\/ep2019.europython.eu\/media\/conference\/slides\/fX8dJsD-distributed-multi-gpu-computing-with-dask-cupy-and-rapids.pdf + (2019)."},{"key":"2649_CR43","doi-asserted-by":"publisher","first-page":"31","DOI":"10.1109\/MCSE.2010.118","volume":"13","author":"S + Behnel","year":"2011","unstructured":"Behnel, S. et al. Cython: the best of + both worlds. Comput. Sci. Eng. 13, 31\u201339 (2011).","journal-title":"Comput. + Sci. Eng."},{"key":"2649_CR44","doi-asserted-by":"crossref","unstructured":"Lam, + S. K., Pitrou, A. & Seibert, S. Numba: a LLVM-based Python JIT compiler. In + Proc. Second Workshop on the LLVM Compiler Infrastructure in HPC, LLVM \u201915 + 7:1\u20137:6 (ACM, 2015).","DOI":"10.1145\/2833157.2833162"},{"key":"2649_CR45","doi-asserted-by":"publisher","first-page":"014001","DOI":"10.1088\/1749-4680\/8\/1\/014001","volume":"8","author":"S + Guelton","year":"2015","unstructured":"Guelton, S. et al. Pythran: enabling + static optimization of scientific Python programs. Comput. Sci. Discov. 8, + 014001 (2015).","journal-title":"Comput. Sci. Discov."},{"key":"2649_CR46","doi-asserted-by":"publisher","first-page":"30","DOI":"10.1109\/MAHC.2008.29","volume":"30","author":"J + Dongarra","year":"2008","unstructured":"Dongarra, J., Golub, G. H., Grosse, + E., Moler, C. & Moore, K. Netlib and NA-Net: building a scientific computing + community. IEEE Ann. Hist. Comput. 30, 30\u201341 (2008).","journal-title":"IEEE + Ann. Hist. Comput."},{"key":"2649_CR47","unstructured":"Barrett, K. A., Chiu, + Y. H., Painter, J. F., Motteler, Z. C. & Dubois, P. F. Basis System, Part + I: Running a Basis Program\u2014A Tutorial for Beginners UCRL-MA-118543, Vol.\u00a01 + (Lawrence Livermore National Laboratory 1995)."},{"key":"2649_CR48","unstructured":"Dubois, + P. F. & Motteler, Z. Basis System, Part II: Basis Language Reference Manual + UCRL-MA-118543, Vol.\u00a02 (Lawrence Livermore National Laboratory, 1995)."},{"key":"2649_CR49","unstructured":"Chiu, + Y. H. & Dubois, P. F. Basis System, Part III: EZN User Manual UCRL-MA-118543, + Vol.\u00a03 (Lawrence Livermore National Laboratory, 1995)."},{"key":"2649_CR50","unstructured":"Chiu, + Y. H. & Dubois, P. F. Basis System, Part IV: EZD User Manual UCRL-MA-118543, + Vol.\u00a04 (Lawrence Livermore National Laboratory, 1995)."},{"key":"2649_CR51","doi-asserted-by":"publisher","first-page":"609","DOI":"10.1063\/1.4823451","volume":"9","author":"DH + Munro","year":"1995","unstructured":"Munro, D. H. & Dubois, P. F. Using the + Yorick interpreted language. Comput. Phys. 9, 609\u2013615 (1995).","journal-title":"Comput. + Phys."},{"key":"2649_CR52","doi-asserted-by":"crossref","first-page":"299","DOI":"10.1080\/10618600.1996.10474713","volume":"5","author":"R + Ihaka","year":"1996","unstructured":"Ihaka, R. & Gentleman, R. R: a language + for data analysis and graphics. J. Comput. Graph. Stat. 5, 299\u2013314 (1996).","journal-title":"J. + Comput. Graph. Stat."},{"key":"2649_CR53","doi-asserted-by":"crossref","unstructured":"Iverson, + K. E. A programming language. In Proc. 1962 Spring Joint Computer Conf. 345\u2013351 + (1962).","DOI":"10.1145\/1460833.1460872"},{"key":"2649_CR54","doi-asserted-by":"crossref","unstructured":"Jenness, + T. et al. LSST data management software development practices and tools. In + Proc. SPIE 10707, Software and Cyberinfrastructure for Astronomy V 1070709 + (SPIE and International Society for Optics and Photonics, 2018).","DOI":"10.1117\/12.2312157"},{"key":"2649_CR55","doi-asserted-by":"publisher","first-page":"103","DOI":"10.1145\/2692956.2663188","volume":"34","author":"ND + Matsakis","year":"2014","unstructured":"Matsakis, N. D. & Klock, F. S. The + Rust language. Ada Letters 34, 103\u2013104 (2014).","journal-title":"Ada + Letters"},{"key":"2649_CR56","doi-asserted-by":"publisher","first-page":"65","DOI":"10.1137\/141000671","volume":"59","author":"J + Bezanson","year":"2017","unstructured":"Bezanson, J., Edelman, A., Karpinski, + S. & Shah, V. B. Julia: a fresh approach to numerical computing. SIAM Rev. + 59, 65\u201398 (2017).","journal-title":"SIAM Rev."},{"key":"2649_CR57","unstructured":"Lattner, + C. & Adve, V. LLVM: a compilation framework for lifelong program analysis + and transformation. In Proc. 2004 Intl Symp. Code Generation and Optimization + (CGO\u201904) 75\u201388 (IEEE, 2004)."}],"container-title":["Nature"],"original-title":[],"language":"en","link":[{"URL":"https:\/\/www.nature.com\/articles\/s41586-020-2649-2.pdf","content-type":"application\/pdf","content-version":"vor","intended-application":"text-mining"},{"URL":"https:\/\/www.nature.com\/articles\/s41586-020-2649-2","content-type":"text\/html","content-version":"vor","intended-application":"text-mining"},{"URL":"https:\/\/www.nature.com\/articles\/s41586-020-2649-2.pdf","content-type":"application\/pdf","content-version":"vor","intended-application":"similarity-checking"}],"deposited":{"date-parts":[[2024,8,14]],"date-time":"2024-08-14T02:15:12Z","timestamp":1723601712000},"score":1,"resource":{"primary":{"URL":"https:\/\/www.nature.com\/articles\/s41586-020-2649-2"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2020,9,16]]},"references-count":57,"journal-issue":{"issue":"7825","published-print":{"date-parts":[[2020,9,17]]}},"alternative-id":["2649"],"URL":"https:\/\/doi.org\/10.1038\/s41586-020-2649-2","relation":{"has-part":[{"id-type":"doi","id":"10.5194\/os-17-997-2021","asserted-by":"object"},{"id-type":"doi","id":"10.5194\/acp-21-18557-2021","asserted-by":"object"},{"id-type":"doi","id":"10.5194\/bg-18-6329-2021","asserted-by":"object"},{"id-type":"doi","id":"10.5194\/amt-17-4891-2024","asserted-by":"object"},{"id-type":"doi","id":"10.5194\/se-14-859-2023","asserted-by":"object"},{"id-type":"doi","id":"10.5194\/amt-18-2481-2025","asserted-by":"object"},{"id-type":"doi","id":"10.5194\/jsss-12-163-2023","asserted-by":"object"}],"has-review":[{"id-type":"doi","id":"10.14293\/S2199-1006.1.SOR-UNCAT.A7759461.v1.RAUGFI","asserted-by":"object"},{"id-type":"doi","id":"10.3410\/f.738677898.793581450","asserted-by":"object"}]},"ISSN":["0028-0836","1476-4687"],"issn-type":[{"type":"print","value":"0028-0836"},{"type":"electronic","value":"1476-4687"}],"subject":[],"published":{"date-parts":[[2020,9,16]]},"assertion":[{"value":"21 + February 2020","order":1,"name":"received","label":"Received","group":{"name":"ArticleHistory","label":"Article + History"}},{"value":"17 June 2020","order":2,"name":"accepted","label":"Accepted","group":{"name":"ArticleHistory","label":"Article + History"}},{"value":"16 September 2020","order":3,"name":"first_online","label":"First + Online","group":{"name":"ArticleHistory","label":"Article History"}},{"value":"The + authors declare no competing interests.","order":1,"name":"Ethics","group":{"name":"EthicsHeading","label":"Competing + interests"}}]}}' + recorded_at: Thu, 30 Oct 2025 20:16:29 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_journal_article_response_2.yml b/test/vcr_cassettes/doi/doi_crossref_journal_article_response_2.yml new file mode 100644 index 0000000000..a94859d9f8 --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_journal_article_response_2.yml @@ -0,0 +1,133 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1021/acs.jcim.5c01488 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:30 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=14jSLSfXCV9Z%2FwxqIxO6drIlbUA5DzDzytZKaRseX55XHLtclWO1SdT%2BZKcKzW0LIZPv6ZTVoM1Rs3MuJaRglADD8vDSlYxwf2lU%2BOqN6HrimA%3D%3D"}]}' + Cf-Ray: + - 996d973c5e5a976a-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1021/acs.jcim.5c01488", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:30 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1021/acs.jcim.5c01488 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:38 GMT + Content-Type: + - application/json + Content-Length: + - '8735' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2025,10,27]],"date-time":"2025-10-27T08:26:59Z","timestamp":1761553619739,"version":"build-2065373602"},"reference-count":54,"publisher":"American + Chemical Society (ACS)","issue":"20","license":[{"start":{"date-parts":[[2025,10,4]],"date-time":"2025-10-04T00:00:00Z","timestamp":1759536000000},"content-version":"vor","delay-in-days":0,"URL":"https:\/\/creativecommons.org\/licenses\/by-nc-nd\/4.0\/"}],"funder":[{"DOI":"10.13039\/501100001659","name":"Deutsche + Forschungsgemeinschaft","doi-asserted-by":"publisher","award":["INST 35\/1597- + 1 FUGG"],"id":[{"id":"10.13039\/501100001659","id-type":"DOI","asserted-by":"publisher"}]},{"DOI":"10.13039\/501100007316","name":"Klaus + Tschira Stiftung","doi-asserted-by":"publisher","id":[{"id":"10.13039\/501100007316","id-type":"DOI","asserted-by":"publisher"}]}],"content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":["J. + Chem. Inf. Model."],"published-print":{"date-parts":[[2025,10,27]]},"DOI":"10.1021\/acs.jcim.5c01488","type":"journal-article","created":{"date-parts":[[2025,10,4]],"date-time":"2025-10-04T13:01:23Z","timestamp":1759582883000},"page":"11215-11231","source":"Crossref","is-referenced-by-count":0,"title":["A + Multiscale Simulation Approach to Compute Protein\u2013Ligand Association + Rate Constants by Combining Brownian Dynamics and Molecular Dynamics"],"prefix":"10.1021","volume":"65","author":[{"ORCID":"https:\/\/orcid.org\/0000-0002-2598-7687","authenticated-orcid":true,"given":"Abraham","family":"Mu\u00f1iz-Chicharro","sequence":"first","affiliation":[{"name":"Molecular + and Cellular Modeling Group","place":["Heidelberg, Germany"]},{"name":"Heidelberg + Institute for Theoretical Studies (HITS)","place":["Heidelberg, Germany"]}]},{"given":"Gaurav + K.","family":"Ganotra","sequence":"additional","affiliation":[{"name":"Molecular + and Cellular Modeling Group","place":["Heidelberg, Germany"]},{"name":"Heidelberg + Institute for Theoretical Studies (HITS)","place":["Heidelberg, Germany"]}]},{"ORCID":"https:\/\/orcid.org\/0000-0001-5951-8670","authenticated-orcid":true,"given":"Rebecca + C.","family":"Wade","sequence":"additional","affiliation":[{"name":"Molecular + and Cellular Modeling Group","place":["Heidelberg, Germany"]},{"name":"Heidelberg + Institute for Theoretical Studies (HITS)","place":["Heidelberg, Germany"]},{"name":"Faculties + of Engineering Sciences and Biosciences, Center for Molecular Biology of Heidelberg + University (ZMBH), DKFZ-ZMBH Alliance, and Interdisciplinary Center for Scientific + Computing (IWR)","place":["Heidelberg, Germany"]},{"name":"Heidelberg University","place":["Heidelberg, + Germany"]}]}],"member":"316","published-online":{"date-parts":[[2025,10,4]]},"reference":[{"key":"ref1\/cit1","doi-asserted-by":"publisher","DOI":"10.1038\/nrd2082"},{"key":"ref2\/cit2","doi-asserted-by":"publisher","DOI":"10.1021\/acs.jmedchem.5b01684"},{"key":"ref3\/cit3","doi-asserted-by":"publisher","DOI":"10.1039\/C6MD00581K"},{"key":"ref4\/cit4","doi-asserted-by":"publisher","DOI":"10.1063\/1.446900"},{"key":"ref5\/cit5","doi-asserted-by":"publisher","DOI":"10.1002\/wcms.1649"},{"key":"ref6\/cit6","doi-asserted-by":"publisher","DOI":"10.1016\/j.bbagen.2024.130740"},{"key":"ref7\/cit7","doi-asserted-by":"publisher","DOI":"10.1038\/358347a0"},{"key":"ref8\/cit8","doi-asserted-by":"publisher","DOI":"10.1042\/bst0240254"},{"key":"ref9\/cit9","doi-asserted-by":"publisher","DOI":"10.1038\/nsb0194-65"},{"key":"ref10\/cit10","doi-asserted-by":"publisher","DOI":"10.1002\/(SICI)1097-0134(19980601)31:4<406::AID-PROT7>3.0.CO;2-F"},{"key":"ref11\/cit11","doi-asserted-by":"publisher","DOI":"10.1021\/acs.jpcb.6b02236"},{"key":"ref12\/cit12","doi-asserted-by":"publisher","DOI":"10.1006\/meth.1998.0588"},{"key":"ref13\/cit13","doi-asserted-by":"publisher","DOI":"10.1006\/jmbi.1999.2919"},{"key":"ref14\/cit14","doi-asserted-by":"publisher","DOI":"10.1006\/jmbi.2000.4404"},{"key":"ref15\/cit15","doi-asserted-by":"publisher","DOI":"10.1529\/biophysj.105.074575"},{"key":"ref16\/cit16","doi-asserted-by":"publisher","DOI":"10.1021\/acs.jctc.1c00673"},{"key":"ref17\/cit17","doi-asserted-by":"publisher","DOI":"10.1021\/ja00078a027"},{"key":"ref18\/cit18","doi-asserted-by":"publisher","DOI":"10.1021\/acs.jpcb.6b09388"},{"key":"ref19\/cit19","doi-asserted-by":"publisher","DOI":"10.1021\/ja00721a051"},{"key":"ref20\/cit20","doi-asserted-by":"publisher","DOI":"10.1021\/acs.jctc.7b00631"},{"key":"ref21\/cit21","doi-asserted-by":"publisher","DOI":"10.1038\/nature06956"},{"key":"ref22\/cit22","doi-asserted-by":"publisher","DOI":"10.1063\/1.5020294"},{"key":"ref23\/cit23","doi-asserted-by":"publisher","DOI":"10.1093\/nar\/28.1.235"},{"key":"ref24\/cit24","doi-asserted-by":"publisher","DOI":"10.1038\/s41467-018-05769-2"},{"key":"ref25\/cit25","doi-asserted-by":"publisher","DOI":"10.1107\/S0907444913009050"},{"key":"ref26\/cit26","doi-asserted-by":"publisher","DOI":"10.1073\/pnas.0908485106"},{"key":"ref27\/cit27","doi-asserted-by":"publisher","DOI":"10.1002\/anie.201801666"},{"key":"ref28\/cit28","doi-asserted-by":"publisher","DOI":"10.1006\/jmbi.1993.1441"},{"key":"ref29\/cit29","doi-asserted-by":"publisher","DOI":"10.1021\/jm070245n"},{"key":"ref30\/cit30","doi-asserted-by":"publisher","DOI":"10.1160\/TH14-10-0877"},{"key":"ref31\/cit31","doi-asserted-by":"publisher","DOI":"10.1021\/jm050101d"},{"key":"ref32\/cit32","doi-asserted-by":"publisher","DOI":"10.1038\/nature05114"},{"key":"ref33\/cit33","doi-asserted-by":"publisher","DOI":"10.1007\/s10822-013-9644-8"},{"key":"ref34\/cit34","doi-asserted-by":"publisher","DOI":"10.1002\/pro.3280"},{"key":"ref35\/cit35","doi-asserted-by":"publisher","DOI":"10.1016\/S0065-3233(03)66002-X"},{"key":"ref36\/cit36","doi-asserted-by":"publisher","DOI":"10.1021\/acs.jctc.1c00302"},{"key":"ref37\/cit37","unstructured":"Ganotra, + G. K. Computational studies of drug-binding kinetics. 2020."},{"key":"ref38\/cit38","doi-asserted-by":"publisher","DOI":"10.1063\/5.0005188"},{"key":"ref39\/cit39","doi-asserted-by":"publisher","DOI":"10.1002\/jcc.20290"},{"key":"ref40\/cit40","doi-asserted-by":"publisher","DOI":"10.1002\/jcc.23971"},{"key":"ref41\/cit41","doi-asserted-by":"publisher","DOI":"10.1021\/jp953109f"},{"key":"ref42\/cit42","doi-asserted-by":"publisher","DOI":"10.1016\/S0006-3495(00)76630-6"},{"key":"ref43\/cit43","doi-asserted-by":"publisher","DOI":"10.1016\/j.isci.2022.105088"},{"key":"ref44\/cit44","doi-asserted-by":"publisher","DOI":"10.1021\/acs.jctc.9b00591"},{"key":"ref45\/cit45","doi-asserted-by":"publisher","DOI":"10.1016\/j.jmgm.2005.12.005"},{"key":"ref46\/cit46","doi-asserted-by":"publisher","DOI":"10.1063\/1.445869"},{"key":"ref47\/cit47","doi-asserted-by":"publisher","DOI":"10.1016\/0021-9991(77)90098-5"},{"key":"ref48\/cit48","unstructured":"Mu\u00f1iz-Chicharro, + A.; Chernova, E.; Ganotra, G. K.; Wade, R. C. SDAMD: a multiscale workflow + to compute protein-ligand binding association rate constants using Brownian + dynamics and molecular dynamics simulations. Manuscript submitted."},{"key":"ref49\/cit49","doi-asserted-by":"publisher","DOI":"10.1371\/journal.pcbi.1000939"},{"key":"ref50\/cit50","doi-asserted-by":"publisher","DOI":"10.1002\/jcc.21836"},{"key":"ref51\/cit51","doi-asserted-by":"publisher","DOI":"10.1073\/pnas.1103547108"},{"key":"ref52\/cit52","doi-asserted-by":"publisher","DOI":"10.3389\/fmolb.2022.922361"},{"key":"ref53\/cit53","doi-asserted-by":"publisher","DOI":"10.1007\/s11239-013-0991-z"},{"key":"ref54\/cit54","doi-asserted-by":"publisher","DOI":"10.32607\/20758251-2009-1-2-26-32"}],"container-title":["Journal + of Chemical Information and Modeling"],"original-title":[],"language":"en","link":[{"URL":"https:\/\/pubs.acs.org\/doi\/pdf\/10.1021\/acs.jcim.5c01488","content-type":"application\/pdf","content-version":"vor","intended-application":"unspecified"},{"URL":"https:\/\/pubs.acs.org\/doi\/pdf\/10.1021\/acs.jcim.5c01488","content-type":"unspecified","content-version":"vor","intended-application":"similarity-checking"}],"deposited":{"date-parts":[[2025,10,27]],"date-time":"2025-10-27T08:11:43Z","timestamp":1761552703000},"score":1,"resource":{"primary":{"URL":"https:\/\/pubs.acs.org\/doi\/10.1021\/acs.jcim.5c01488"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2025,10,4]]},"references-count":54,"journal-issue":{"issue":"20","published-print":{"date-parts":[[2025,10,27]]}},"alternative-id":["10.1021\/acs.jcim.5c01488"],"URL":"https:\/\/doi.org\/10.1021\/acs.jcim.5c01488","relation":{},"ISSN":["1549-9596","1549-960X"],"issn-type":[{"type":"print","value":"1549-9596"},{"type":"electronic","value":"1549-960X"}],"subject":[],"published":{"date-parts":[[2025,10,4]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:38 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_preprint_response_1.yml b/test/vcr_cassettes/doi/doi_crossref_preprint_response_1.yml new file mode 100644 index 0000000000..1c98199a2c --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_preprint_response_1.yml @@ -0,0 +1,141 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.20944/preprints201909.0043.v1 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:28 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=M1sBNzSDkkSKxf3x2OYHOhje%2FaXFvXmkXk2vMByiHtXzCKPSkxmiEI%2FTGZwpNt64K6qpjUBINl69lyd39e7ssuYsl%2FtTy%2FsgaPNFtRNcgQvObQ%3D%3D"}]}' + Cf-Ray: + - 996d97334fa71c11-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.20944/preprints201909.0043.v1", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:28 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.20944/preprints201909.0043.v1 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:29 GMT + Content-Type: + - application/json + Content-Length: + - '5014' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2025,2,21]],"date-time":"2025-02-21T00:23:27Z","timestamp":1740097407763,"version":"3.37.3"},"posted":{"date-parts":[[2019,9,4]]},"group-title":"LIFE + SCIENCES","reference-count":0,"publisher":"MDPI AG","license":[{"start":{"date-parts":[[2019,9,4]],"date-time":"2019-09-04T00:00:00Z","timestamp":1567555200000},"content-version":"unspecified","delay-in-days":0,"URL":"http:\/\/creativecommons.org\/licenses\/by\/4.0"}],"content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"accepted":{"date-parts":[[2019,9,3]]},"abstract":"Myalgic + Encephalomyelitis\/Chronic Fatigue Syndrome (ME\/CFS) is an enigmatic condition + characterized by fatigue that is unaided by rest and by exacerbation of symptoms + after exertion (post-exertional malaise or &ldquo;PEM&rdquo;). There + is no definitive molecular marker or known underlying pathological mechanism + for the condition. Increasing evidence for aberrant energy metabolism suggests + a role for mitochondrial dysfunction in ME\/CFS. Our objective was therefore + to measure mitochondrial function and cellular stress sensing in actively + metabolising patient blood cells. We immortalized lymphoblasts isolated from + 51 ME\/CFS patients diagnosed according to the Canadian Consensus Criteria + and an age- and gender-matched control group. Parameters of mitochondrial + function and energy stress sensing were assessed by Seahorse extracellular + flux analysis, proteomics, and an array of additional biochemical assays. + As a proportion of the basal oxygen consumption rate (OCR), the rate of ATP + synthesis by Complex V was significantly reduced in ME\/CFS lymphoblasts, + while significant elevations were observed in Complex I OCR, maximum OCR, + spare respiratory capacity, nonmitochondrial OCR and &ldquo;proton leak&rdquo; + as a proportion of the basal OCR. This was accompanied by an elevation of + mitochondrial membrane potential, chronically hyperactivated TOR Complex I + stress signalling and upregulated expression of mitochondrial respiratory + complexes, fatty acid transporters and enzymes of the &beta;-oxidation + and TCA cycles. By contrast, mitochondrial mass and genome copy number, as + well as glycolytic rates and steady state ATP levels were unchanged. Our results + suggest a model in which ME\/CFS lymphoblasts have a Complex V defect accompanied + by compensatory upregulation of their respiratory capacity that includes the + mitochondrial respiratory complexes, membrane transporters and enzymes involved + in fatty acid &beta;-oxidation. This homeostatically returns ATP synthesis + and steady state levels to &ldquo;normal&rdquo; in resting cells, + but may leave them unable to adequately respond to acute increases in energy + demand as the relevant homeostatic pathways are already activated.<\/jats:p>","DOI":"10.20944\/preprints201909.0043.v1","type":"posted-content","created":{"date-parts":[[2019,9,5]],"date-time":"2019-09-05T04:28:52Z","timestamp":1567657732000},"source":"Crossref","is-referenced-by-count":2,"title":["An + Isolated Complex V Inefficiency and Dysregulated Mitochondrial Function in + Immortalized Lymphocytes from ME\/CFS Patients"],"prefix":"10.20944","author":[{"given":"Daniel","family":"Missailidis","sequence":"first","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0002-7604-3985","authenticated-orcid":false,"given":"Sarah","family":"Annesley","sequence":"additional","affiliation":[]},{"given":"Claire","family":"Allan","sequence":"additional","affiliation":[]},{"given":"Oana","family":"Sanislav","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0003-2211-989X","authenticated-orcid":false,"given":"Brett","family":"Lidbury","sequence":"additional","affiliation":[]},{"given":"Don","family":"Lewis","sequence":"additional","affiliation":[]},{"ORCID":"https:\/\/orcid.org\/0000-0003-1884-6306","authenticated-orcid":false,"given":"Paul","family":"Fisher","sequence":"additional","affiliation":[]}],"member":"1968","container-title":[],"original-title":[],"deposited":{"date-parts":[[2020,3,10]],"date-time":"2020-03-10T06:22:28Z","timestamp":1583821348000},"score":1,"resource":{"primary":{"URL":"https:\/\/www.preprints.org\/manuscript\/201909.0043\/v1"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2019,9,4]]},"references-count":0,"URL":"https:\/\/doi.org\/10.20944\/preprints201909.0043.v1","relation":{"is-version-of":[{"id-type":"doi","id":"10.20944\/preprints201909.0043.v2","asserted-by":"subject"},{"id-type":"doi","id":"10.20944\/preprints201909.0043.v3","asserted-by":"subject"}],"is-preprint-of":[{"id-type":"doi","id":"10.3390\/ijms21031074","asserted-by":"subject"}],"has-version":[{"id-type":"doi","id":"10.20944\/preprints201909.0043.v2","asserted-by":"object"},{"id-type":"doi","id":"10.20944\/preprints201909.0043.v3","asserted-by":"object"}]},"subject":[],"published":{"date-parts":[[2019,9,4]]},"subtype":"preprint"}}' + recorded_at: Thu, 30 Oct 2025 20:16:29 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_1.yml b/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_1.yml new file mode 100644 index 0000000000..468fbf2e1e --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_1.yml @@ -0,0 +1,154 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1117/12.2275959 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:41 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=WDzVS9YehTcd4S5xKc5vaueniUW9dNMperq4xB3%2BrAcOaDM5z1Kp%2FP7NcCiOvoveotb3lPdCdS5hxHFGST5h9kKY%2BmmOn2XNDa81cTxugGLyyw%3D%3D"}]}' + Cf-Ray: + - 996d97823b4cd289-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1117/12.2275959", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:41 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1117/12.2275959 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:41 GMT + Content-Type: + - application/json + Content-Length: + - '9924' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2024,10,23]],"date-time":"2024-10-23T09:55:38Z","timestamp":1729677338309,"version":"3.28.0"},"reference-count":54,"publisher":"SPIE","content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"published-print":{"date-parts":[[2017,9,26]]},"DOI":"10.1117\/12.2275959","type":"proceedings-article","created":{"date-parts":[[2017,9,19]],"date-time":"2017-09-19T19:58:22Z","timestamp":1505851102000},"page":"24","source":"Crossref","is-referenced-by-count":4,"title":["The + NOVA project: maximizing beam time efficiency through synergistic analyses + of SR\u03bcCT data"],"prefix":"10.1117","author":[{"given":"Sebastian","family":"Schmelzle","sequence":"first","affiliation":[]},{"given":"Thomas","family":"van + de Kamp","sequence":"first","affiliation":[]},{"given":"Michael","family":"Heethoff","sequence":"first","affiliation":[]},{"given":"Vincent","family":"Heuveline","sequence":"first","affiliation":[]},{"given":"Philipp","family":"L\u00f6sel","sequence":"first","affiliation":[]},{"given":"J\u00fcrgen","family":"Becker","sequence":"first","affiliation":[]},{"given":"Felix","family":"Beckmann","sequence":"first","affiliation":[]},{"given":"Frank","family":"Schluenzen","sequence":"first","affiliation":[]},{"given":"J\u00f6rg + U.","family":"Hammel","sequence":"first","affiliation":[]},{"given":"Andreas","family":"Kopmann","sequence":"first","affiliation":[]},{"given":"Wolfgang","family":"Mexner","sequence":"first","affiliation":[]},{"given":"Matthias","family":"Vogelgesang","sequence":"first","affiliation":[]},{"given":"Nicholas + T.","family":"Jerome","sequence":"first","affiliation":[]},{"given":"Oliver","family":"Betz","sequence":"first","affiliation":[]},{"given":"Rolf","family":"Beutel","sequence":"first","affiliation":[]},{"given":"Benjamin","family":"Wipfler","sequence":"first","affiliation":[]},{"given":"Alexander","family":"Blanke","sequence":"first","affiliation":[]},{"given":"Steffen","family":"Harzsch","sequence":"first","affiliation":[]},{"given":"Marie","family":"H\u00f6rnig","sequence":"first","affiliation":[]},{"given":"Tilo","family":"Baumbach","sequence":"first","affiliation":[]}],"member":"189","reference":[{"doi-asserted-by":"publisher","key":"c1","DOI":"10.1111\/jmi.2007.227.issue-1"},{"key":"c2","first-page":"70781U-1","article-title":"Micro-computer + tomography and a renaissance of insect morphology","volume":"7078","author":"Friedrich","year":"2008"},{"doi-asserted-by":"publisher","key":"c3","DOI":"10.1016\/j.asd.2009.07.001"},{"doi-asserted-by":"publisher","key":"c4","DOI":"10.1016\/j.jcz.2014.09.002"},{"doi-asserted-by":"publisher","key":"c5","DOI":"10.1002\/jmor.v272.9"},{"key":"c6","first-page":"147","article-title":"Insect + imaging at the ANKA Synchrotron Radiation Facility","volume":"25","author":"van + de Kamp","year":"2013","journal-title":"Entomologie heute"},{"doi-asserted-by":"publisher","key":"c7","DOI":"10.1002\/jmor.v277.4"},{"key":"c8","first-page":"1","article-title":"Morphological + and molecular evidence converging upon a robust phylogeny of the megadiverse + Holometabola","volume":"26","author":"Beutel","year":"2011","journal-title":"Cladistics"},{"year":"2017","author":"Mexner","article-title":"OpenGL\u00ae + API based analysis of large datasets in a cloud environment","key":"c9"},{"key":"c10","article-title":"Enhancing + a diffusion algorithm for 4D image segmentation using local information","volume":"9784","author":"L\u00f6sel","year":"2016"},{"doi-asserted-by":"publisher","key":"c11","DOI":"10.1007\/978-3-319-52280-7"},{"doi-asserted-by":"publisher","key":"c12","DOI":"10.1111\/cla.2012.28.issue-6"},{"doi-asserted-by":"publisher","key":"c13","DOI":"10.1007\/s13127-012-0097-z"},{"doi-asserted-by":"publisher","key":"c14","DOI":"10.1111\/syen.12012"},{"doi-asserted-by":"publisher","key":"c15","DOI":"10.1186\/1742-9994-11-16"},{"doi-asserted-by":"publisher","key":"c16","DOI":"10.1016\/j.asd.2013.10.003"},{"doi-asserted-by":"publisher","key":"c17","DOI":"10.1093\/molbev\/mst199"},{"doi-asserted-by":"publisher","key":"c18","DOI":"10.1111\/syen.2015.40.issue-2"},{"key":"c19","first-page":"20151033","article-title":"Structural + mouthpart interaction evolved already in the earliest lineages of insects","volume":"282","author":"Blanke","year":"2015"},{"doi-asserted-by":"publisher","key":"c20","DOI":"10.1093\/sysbio\/sys091"},{"doi-asserted-by":"publisher","key":"c21","DOI":"10.1002\/jmor.v270:12"},{"key":"c22","doi-asserted-by":"crossref","first-page":"910","DOI":"10.1002\/jmor.10841","article-title":"Comparative + morphology of the head of selected sporophagous and non-sporophagous aleocharinae + (Coleoptera: Staphylinidae): Musculature and hypopharynx-prementum complex","volume":"271","author":"Weide","year":"2010","journal-title":"J. + Morph"},{"doi-asserted-by":"publisher","key":"c23","DOI":"10.1111\/azo.2013.95.issue-1"},{"doi-asserted-by":"publisher","key":"c24","DOI":"10.1242\/jeb.092742"},{"doi-asserted-by":"publisher","key":"c25","DOI":"10.1016\/j.asd.2012.09.005"},{"doi-asserted-by":"publisher","key":"c26","DOI":"10.1016\/j.jcz.2012.09.003"},{"key":"c27","first-page":"1","article-title":"Brain + architecture of the Pacific White Shrimp Penaeus vannamei Boone, 1931 (Malacostraca, + Dendrobranchiata): correspondence of brain structure and sensory input?","author":"Meth","year":"2017","journal-title":"Cell + and Tissue Research"},{"doi-asserted-by":"publisher","key":"c28","DOI":"10.1002\/cne.23741"},{"key":"c29","first-page":"1","article-title":"What + nymphal morphology can tell us about parental investment \u2013 a group of + cockroach hatchlings in Baltic Amber documented by a multi-method approach","author":"H\u00f6rnig","year":"2016","journal-title":"Palaeontologia + Electronica 19.1.5A"},{"doi-asserted-by":"publisher","key":"c30","DOI":"10.1038\/s41598-017-01496-8"},{"doi-asserted-by":"publisher","key":"c31","DOI":"10.1038\/srep42345"},{"doi-asserted-by":"publisher","key":"c32","DOI":"10.1073\/pnas.1308650111"},{"key":"c33","first-page":"37","article-title":"X-ray + radiography of a spraying stick insect (Phasmatodea)","volume":"27","author":"van + de Kamp","year":"2015","journal-title":"Entomologie heute"},{"doi-asserted-by":"publisher","key":"c34","DOI":"10.1111\/zoj.2012.165.issue-4"},{"doi-asserted-by":"publisher","key":"c35","DOI":"10.1371\/journal.pone.0080560"},{"doi-asserted-by":"publisher","key":"c36","DOI":"10.11646\/zootaxa.3860.5"},{"key":"c37","first-page":"151","article-title":"Scanning + the past \u2013synchrotron X-ray microtomography of fossil wasps in amber","volume":"26","author":"van + de Kamp","year":"2014","journal-title":"Entomologie heute"},{"issue":"e12129","key":"c38","first-page":"1","article-title":"Preservation + of three-dimensional anatomy in phosphatized fossil arthropods enriches evolutionary + inference","volume":"5","author":"Schwermann","year":"2016","journal-title":"eLife"},{"key":"c39","first-page":"127","article-title":"The + fossil insects of the Quercy region: a historical review","volume":"28","author":"Schwermann","year":"2016","journal-title":"Entomologie + heute"},{"doi-asserted-by":"publisher","key":"c40","DOI":"10.1038\/srep41413"},{"doi-asserted-by":"publisher","key":"c41","DOI":"10.1126\/science.1204245"},{"doi-asserted-by":"publisher","key":"c42","DOI":"10.1371\/journal.pone.0102355"},{"doi-asserted-by":"publisher","key":"c43","DOI":"10.1016\/j.asd.2015.07.004"},{"key":"c44","article-title":"Adaptive + trends in malacostracan brain form and function related to behavior","volume":"3","author":"Sandeman","year":"2014"},{"year":"2008","author":"Beckmann","article-title":"The + GKSS Beamlines at PETRA III and DORIS III","key":"c45"},{"doi-asserted-by":"publisher","key":"c46","DOI":"10.1154\/1.3428364"},{"year":"2010","author":"Haibel","article-title":"Micro- + and nano-tomography at the GKSS Imaging Beamline at PETRA III","key":"c47"},{"year":"2014","author":"Hipp","article-title":"Grating-Based + X-Ray Phase-Contrast Imaging at PETRA III","key":"c48"},{"key":"c49","first-page":"92120O","article-title":"P05 + imaging beamline at PETRA III: first results","author":"Greving","year":"2014","journal-title":"Developments + in X-Ray Tomography IX 9212"},{"key":"c50","article-title":"Single-grating + interferometer for high-resolution phase-contrast imaging at synchrotron radiation + sources","volume":"9967","author":"Hipp","year":"2016","journal-title":"SPIE + Optical Engineering + Applications"},{"year":"2015","author":"Wilde","article-title":"Micro-CT + at the Imaging Beamline P05 at PETRA III","key":"c51"},{"key":"c52","first-page":"152","article-title":"WAVE: + a 3D online previewing framework for big data archives","author":"Tan Jerome","year":"2017"},{"doi-asserted-by":"publisher","key":"c53","DOI":"10.5220\/0006262903300334"},{"key":"c54","first-page":"1","article-title":"Surface + area\u2013volume ratios in insects","author":"K\u00fchsel","year":"2016","journal-title":"Insect + Science"}],"event":{"name":"Developments in X-Ray Tomography XI","start":{"date-parts":[[2017,8,6]]},"location":"San + Diego, United States","end":{"date-parts":[[2017,8,10]]}},"container-title":["Developments + in X-Ray Tomography XI"],"original-title":[],"deposited":{"date-parts":[[2024,6,27]],"date-time":"2024-06-27T02:25:34Z","timestamp":1719455134000},"score":1,"resource":{"primary":{"URL":"https:\/\/www.spiedigitallibrary.org\/conference-proceedings-of-spie\/10391\/2275959\/The-NOVA-project--maximizing-beam-time-efficiency-through-synergistic\/10.1117\/12.2275959.full"}},"subtitle":[],"editor":[{"given":"Bert","family":"M\u00fcller","sequence":"first","affiliation":[]},{"given":"Ge","family":"Wang","sequence":"first","affiliation":[]}],"short-title":[],"issued":{"date-parts":[[2017,9,26]]},"references-count":54,"URL":"https:\/\/doi.org\/10.1117\/12.2275959","relation":{},"subject":[],"published":{"date-parts":[[2017,9,26]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:41 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_2.yml b/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_2.yml new file mode 100644 index 0000000000..b574a175de --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_2.yml @@ -0,0 +1,147 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1145/3292500.3330675 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:42 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=K0mmh6ghNypyaqNBHeRnj1kSolUAtGwe97H9twcoatrh9fG7%2FcZpqjX%2F3j7NMjV2sxvI8Se6%2Bzeig9pmQbvspbrLiWmVRdlhh9Fc6gaUJd0o7w%3D%3D"}]}' + Cf-Ray: + - 996d9786496dd351-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1145/3292500.3330675", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:42 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1145/3292500.3330675 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:42 GMT + Content-Type: + - application/json + Content-Length: + - '7001' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2025,6,18]],"date-time":"2025-06-18T04:32:00Z","timestamp":1750221120476,"version":"3.41.0"},"publisher-location":"New + York, NY, USA","reference-count":29,"publisher":"ACM","license":[{"start":{"date-parts":[[2019,7,25]],"date-time":"2019-07-25T00:00:00Z","timestamp":1564012800000},"content-version":"vor","delay-in-days":0,"URL":"https:\/\/www.acm.org\/publications\/policies\/copyright_policy#Background"}],"content-domain":{"domain":["dl.acm.org"],"crossmark-restriction":true},"short-container-title":[],"published-print":{"date-parts":[[2019,7,25]]},"DOI":"10.1145\/3292500.3330675","type":"proceedings-article","created":{"date-parts":[[2019,7,26]],"date-time":"2019-07-26T13:17:26Z","timestamp":1564147046000},"page":"3153-3161","update-policy":"https:\/\/doi.org\/10.1145\/crossmark-policy","source":"Crossref","is-referenced-by-count":12,"title":["Whole + Page Optimization with Global Constraints"],"prefix":"10.1145","author":[{"given":"Weicong","family":"Ding","sequence":"first","affiliation":[{"name":"Amazon.com, + Seattle, WA, USA"}]},{"given":"Dinesh","family":"Govindaraj","sequence":"additional","affiliation":[{"name":"Amazon.com, + Seattle, WA, USA"}]},{"given":"S V N","family":"Vishwanathan","sequence":"additional","affiliation":[{"name":"Amazon.com, + Seattle, WA, USA"}]}],"member":"320","published-online":{"date-parts":[[2019,7,25]]},"reference":[{"doi-asserted-by":"publisher","key":"e_1_3_2_1_1_1","DOI":"10.1145\/2740908.2745398"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_2_1","DOI":"10.1145\/1526709.1526713"},{"unstructured":"Shipra + Agrawal and Nikhil Devanur. 2016. Linear contextual bandits with knapsacks. + In Advances in Neural Information Processing Systems. 3450--3458. Shipra + Agrawal and Nikhil Devanur. 2016. Linear contextual bandits with knapsacks. + In Advances in Neural Information Processing Systems. 3450--3458.","key":"e_1_3_2_1_3_1"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_4_1","DOI":"10.1145\/2124295.2124337"},{"volume-title":"Constrained + Multi-Slot Optimization for Ranking Recommendations. arXiv preprint arXiv:1602.04391","year":"2016","author":"Basu + Kinjal","key":"e_1_3_2_1_5_1"},{"unstructured":"Kinjal Basu Ankan Saha and + Shaunak Chatterjee. 2017. Large-Scale Quadratically Constrained Quadratic + Program via Low-Discrepancy Sequences. In Advances in Neural Information Processing + Systems. 2297--2307. Kinjal Basu Ankan Saha and Shaunak Chatterjee. 2017. + Large-Scale Quadratically Constrained Quadratic Program via Low-Discrepancy + Sequences. In Advances in Neural Information Processing Systems. 2297--2307.","key":"e_1_3_2_1_6_1"},{"unstructured":"Laming + Chen Guoxin Zhang and Hanning Zhou. 2018. Improving the Diversity of Top-N + Recommendation via Determinantal Point Process. In Advances in Neural Information + Processing Systems. Laming Chen Guoxin Zhang and Hanning Zhou. 2018. Improving + the Diversity of Top-N Recommendation via Determinantal Point Process. In + Advances in Neural Information Processing Systems.","key":"e_1_3_2_1_7_1"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_8_1","DOI":"10.1145\/2487575.2488197"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_9_1","DOI":"10.1145\/3132847.3133034"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_10_1","DOI":"10.1145\/1390334.1390446"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_11_1","DOI":"10.1145\/2959100.2959190"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_12_1","DOI":"10.1145\/1242572.1242610"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_13_1","DOI":"10.5555\/3174304.3175454"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_14_1","DOI":"10.1145\/2892563"},{"volume-title":"Proceedings + of International Conference on Machine Learning","year":"2010","author":"Graepel + Thore","key":"e_1_3_2_1_15_1"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_16_1","DOI":"10.1145\/2939672.2939692"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_17_1","DOI":"10.1145\/2648584.2648589"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_18_1","DOI":"10.1145\/3097983.3098184"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_19_1","DOI":"10.1145\/2939672.2939691"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_20_1","DOI":"10.1145\/1944339.1944341"},{"volume-title":"Adaptive + Algorithms for Online Convex Optimization with Long-term Constraints. In International + Conference on Machine Learning. 402--411","year":"2016","author":"Jenatton + Rodolphe","key":"e_1_3_2_1_21_1"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_22_1","DOI":"10.5555\/2503308.2503322"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_23_1","DOI":"10.1145\/3219819.3220072"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_24_1","DOI":"10.1145\/3097983.3098025"},{"volume-title":"Safety-Aware + Algorithms for Adversarial Contextual Bandit. In International Conference + on Machine Learning. 3280--3288","year":"2017","author":"Sun Wen","key":"e_1_3_2_1_25_1"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_26_1","DOI":"10.1145\/2959100.2959171"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_27_1","DOI":"10.1145\/2835776.2835824"},{"doi-asserted-by":"publisher","key":"e_1_3_2_1_28_1","DOI":"10.1145\/3269206.3272018"},{"unstructured":"Hao + Yu Michael Neely and Xiaohan Wei. 2017. Online Convex Optimization with Stochastic + Constraints. In Advances in Neural Information Processing Systems. 1427--1437. Hao + Yu Michael Neely and Xiaohan Wei. 2017. Online Convex Optimization with Stochastic + Constraints. In Advances in Neural Information Processing Systems. 1427--1437.","key":"e_1_3_2_1_29_1"}],"event":{"sponsor":["SIGMOD + ACM Special Interest Group on Management of Data","SIGKDD ACM Special Interest + Group on Knowledge Discovery in Data"],"acronym":"KDD ''19","name":"KDD ''19: + The 25th ACM SIGKDD Conference on Knowledge Discovery and Data Mining","location":"Anchorage + AK USA"},"container-title":["Proceedings of the 25th ACM SIGKDD International + Conference on Knowledge Discovery & Data Mining"],"original-title":[],"link":[{"URL":"https:\/\/dl.acm.org\/doi\/10.1145\/3292500.3330675","content-type":"unspecified","content-version":"vor","intended-application":"text-mining"},{"URL":"https:\/\/dl.acm.org\/doi\/pdf\/10.1145\/3292500.3330675","content-type":"unspecified","content-version":"vor","intended-application":"similarity-checking"}],"deposited":{"date-parts":[[2025,6,18]],"date-time":"2025-06-18T01:02:09Z","timestamp":1750208529000},"score":1,"resource":{"primary":{"URL":"https:\/\/dl.acm.org\/doi\/10.1145\/3292500.3330675"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2019,7,25]]},"references-count":29,"alternative-id":["10.1145\/3292500.3330675","10.1145\/3292500"],"URL":"https:\/\/doi.org\/10.1145\/3292500.3330675","relation":{},"subject":[],"published":{"date-parts":[[2019,7,25]]},"assertion":[{"value":"2019-07-25","order":2,"name":"published","label":"Published","group":{"name":"publication_history","label":"Publication + History"}}]}}' + recorded_at: Thu, 30 Oct 2025 20:16:42 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_3.yml b/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_3.yml new file mode 100644 index 0000000000..6ff7795d3b --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_proceedings_article_response_3.yml @@ -0,0 +1,113 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1063/1.2128263 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:42 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=ysotTDZX%2FAnrHuavrlc4C9GsV0ddwEMgpNxE6OI%2BYGdAYqmSw40EQupOgJsWW95erEimu3fagu4pNul4sn8kzWiyOFiXipIxBODr46vbEYk%3D"}]}' + Cf-Ray: + - 996d978b3b2d695e-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1063/1.2128263", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:42 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.1063/1.2128263 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:43 GMT + Content-Type: + - application/json + Content-Length: + - '1402' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2024,8,6]],"date-time":"2024-08-06T00:01:12Z","timestamp":1722902472549},"reference-count":0,"publisher":"AIP","content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"published-print":{"date-parts":[[2005]]},"DOI":"10.1063\/1.2128263","type":"proceedings-article","created":{"date-parts":[[2005,11,1]],"date-time":"2005-11-01T14:06:18Z","timestamp":1130853978000},"page":"29-34","source":"Crossref","is-referenced-by-count":4,"title":["Conference + Recommendations"],"prefix":"10.1063","volume":"795","author":[{"name":"Conference + organizers","sequence":"first","affiliation":[]}],"member":"317","event":{"name":"WOMEN + IN PHYSICS: 2nd IUPAP International Conference on Women in Physics","location":"Rio + de Janeiro (Brazil)"},"container-title":["AIP Conference Proceedings"],"original-title":[],"deposited":{"date-parts":[[2023,4,20]],"date-time":"2023-04-20T10:00:04Z","timestamp":1681984804000},"score":1,"resource":{"primary":{"URL":"https:\/\/pubs.aip.org\/aip\/acp\/article\/795\/1\/29-34\/624381"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2005]]},"references-count":0,"URL":"https:\/\/doi.org\/10.1063\/1.2128263","relation":{},"ISSN":["0094-243X"],"issn-type":[{"type":"print","value":"0094-243X"}],"subject":[],"published":{"date-parts":[[2005]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:43 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_crossref_proceedings_response_1.yml b/test/vcr_cassettes/doi/doi_crossref_proceedings_response_1.yml new file mode 100644 index 0000000000..9d2c3137d9 --- /dev/null +++ b/test/vcr_cassettes/doi/doi_crossref_proceedings_response_1.yml @@ -0,0 +1,113 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.18653/v1/w18-08 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:40 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=ZAExPgMIw4IdS44UXgq%2Fo6pc3zyGBcHqTVnszaLS5vM9lis7y8V1RAuyU769jpa9Iezdal4%2FP%2BUWuvCZuG7TQ8bB954Zrj9OWKZeHxGZ6WTO3A%3D%3D"}]}' + Cf-Ray: + - 996d977d6c953a7c-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.18653/v1/w18-08", + "RA": "Crossref" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:40 GMT +- request: + method: get + uri: https://api.crossref.org/works/10.18653/v1/w18-08 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.crossref.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:41 GMT + Content-Type: + - application/json + Content-Length: + - '1376' + Connection: + - keep-alive + Access-Control-Expose-Headers: + - Link + Access-Control-Allow-Headers: + - X-Requested-With, Accept, Accept-Encoding, Accept-Charset, Accept-Language, + Accept-Ranges, Cache-Control + Access-Control-Allow-Origin: + - "*" + Vary: + - Accept-Encoding + Server: + - Jetty(9.4.40.v20210413) + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + X-Api-Pool: + - public + Permissions-Policy: + - interest-cohort=() + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"work","message-version":"1.0.0","message":{"indexed":{"date-parts":[[2022,4,3]],"date-time":"2022-04-03T09:15:56Z","timestamp":1648977356913},"publisher-location":"Stroudsburg, + PA, USA","reference-count":0,"publisher":"Association for Computational Linguistics","content-domain":{"domain":[],"crossmark-restriction":false},"short-container-title":[],"published-print":{"date-parts":[[2018]]},"DOI":"10.18653\/v1\/w18-08","type":"proceedings","created":{"date-parts":[[2018,5,30]],"date-time":"2018-05-30T00:48:35Z","timestamp":1527641315000},"source":"Crossref","is-referenced-by-count":0,"title":["Proceedings + of the Second ACL Workshop on Ethics in Natural Language Processing"],"prefix":"10.18653","member":"1643","event":{"name":"Proceedings + of the Second ACL Workshop on Ethics in Natural Language Processing","location":"New + Orleans, Louisiana, USA","start":{"date-parts":[[2018,6]]},"end":{"date-parts":[[2018,6]]}},"container-title":[],"original-title":[],"deposited":{"date-parts":[[2018,5,30]],"date-time":"2018-05-30T00:48:36Z","timestamp":1527641316000},"score":1,"resource":{"primary":{"URL":"http:\/\/aclweb.org\/anthology\/W18-08"}},"subtitle":[],"short-title":[],"issued":{"date-parts":[[2018]]},"references-count":0,"URL":"https:\/\/doi.org\/10.18653\/v1\/w18-08","relation":{},"subject":[],"published":{"date-parts":[[2018]]}}}' + recorded_at: Thu, 30 Oct 2025 20:16:41 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_datacite_response_1.yml b/test/vcr_cassettes/doi/doi_datacite_response_1.yml new file mode 100644 index 0000000000..4f372904ac --- /dev/null +++ b/test/vcr_cassettes/doi/doi_datacite_response_1.yml @@ -0,0 +1,127 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.5281/zenodo.16736322 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:55 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=5c7qyP1fi3wLPlBYNUL8Ncf9%2BWiGAfNZmXKoS2beit4OjXf9gbi5dnY7vCNEzX%2B8%2Fg%2F%2F5aiwxhn6sP0uDnANUHP4BrBLxLZgMUuMbx1lJSVINg%3D%3D"}]}' + Cf-Ray: + - 996d97db1e43d27d-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.5281/zenodo.16736322", + "RA": "DataCite" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:55 GMT +- request: + method: get + uri: https://api.datacite.org/dois/10.5281/zenodo.16736322 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.datacite.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:55 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Status: + - 200 OK + X-Anonymous-Consumer: + - 'true' + Cache-Control: + - max-age=0, private, must-revalidate + Vary: + - Accept,Accept-Encoding + Referrer-Policy: + - strict-origin-when-cross-origin + X-Permitted-Cross-Domain-Policies: + - none + X-Xss-Protection: + - '0' + X-Request-Id: + - 2c0ec519-5883-463d-982a-b3b1c61a591a + Etag: + - W/"c3dcde8feaa5f68e9ea917f20d858d14" + X-Frame-Options: + - SAMEORIGIN + X-Runtime: + - '0.049197' + X-Content-Type-Options: + - nosniff + X-Powered-By: + - Phusion Passenger(R) 6.1.0 + Server: + - nginx/1.24.0 + Phusion Passenger(R) 6.1.0 + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Methods: + - GET, POST, PUT, PATCH, DELETE, OPTIONS + Access-Control-Allow-Headers: + - Accept,Access-Control-Allow-Origin,Access-Control-Expose-Headers,Access-Control-Allow-Methods,Access-Control-Allow-Headers,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With + Access-Control-Expose-Headers: + - Authorization + body: + encoding: ASCII-8BIT + string: !binary |- + eyJkYXRhIjp7ImlkIjoiMTAuNTI4MS96ZW5vZG8uMTY3MzYzMjIiLCJ0eXBlIjoiZG9pcyIsImF0dHJpYnV0ZXMiOnsiZG9pIjoiMTAuNTI4MS96ZW5vZG8uMTY3MzYzMjIiLCJwcmVmaXgiOiIxMC41MjgxIiwic3VmZml4IjoiemVub2RvLjE2NzM2MzIyIiwiaWRlbnRpZmllcnMiOlt7ImlkZW50aWZpZXIiOiJvYWk6emVub2RvLm9yZzoxNjczNjMyMiIsImlkZW50aWZpZXJUeXBlIjoib2FpIn1dLCJhbHRlcm5hdGVJZGVudGlmaWVycyI6W3siYWx0ZXJuYXRlSWRlbnRpZmllclR5cGUiOiJvYWkiLCJhbHRlcm5hdGVJZGVudGlmaWVyIjoib2FpOnplbm9kby5vcmc6MTY3MzYzMjIifV0sImNyZWF0b3JzIjpbeyJuYW1lIjoiSHUsIFhpYW9taW5nIiwibmFtZVR5cGUiOiJQZXJzb25hbCIsImdpdmVuTmFtZSI6IlhpYW9taW5nIiwiZmFtaWx5TmFtZSI6Ikh1IiwiYWZmaWxpYXRpb24iOlsiSGVpZGVsYmVyZyBJbnN0aXR1dGUgZm9yIFRoZW9yZXRpY2FsIFN0dWRpZXMgKEhJVFMpLCBIZWlkZWxiZXJnIl0sIm5hbWVJZGVudGlmaWVycyI6W3sibmFtZUlkZW50aWZpZXIiOiIwMDAwLTAwMDItODMxOC0zMjIyIiwibmFtZUlkZW50aWZpZXJTY2hlbWUiOiJPUkNJRCJ9XX0seyJuYW1lIjoiT3dlbiwgU3R1YXJ0IiwibmFtZVR5cGUiOiJQZXJzb25hbCIsImdpdmVuTmFtZSI6IlN0dWFydCIsImZhbWlseU5hbWUiOiJPd2VuIiwiYWZmaWxpYXRpb24iOlsiVGhlIFVuaXZlcnNpdHkgb2YgTWFuY2hlc3RlciJdLCJuYW1lSWRlbnRpZmllcnMiOlt7Im5hbWVJZGVudGlmaWVyIjoiMDAwMC0wMDAzLTIxMzAtMDg2NSIsIm5hbWVJZGVudGlmaWVyU2NoZW1lIjoiT1JDSUQifV19LHsibmFtZSI6Ik1laW5la2UsIEZyYW5rIiwibmFtZVR5cGUiOiJQZXJzb25hbCIsImdpdmVuTmFtZSI6IkZyYW5rIiwiZmFtaWx5TmFtZSI6Ik1laW5la2UiLCJhZmZpbGlhdGlvbiI6WyJVbml2ZXJzaXTDpHQgTGVpcHppZywgSU1JU0UiXSwibmFtZUlkZW50aWZpZXJzIjpbeyJuYW1lSWRlbnRpZmllciI6IjAwMDAtMDAwMi05MjU2LTc1NDMiLCJuYW1lSWRlbnRpZmllclNjaGVtZSI6Ik9SQ0lEIn1dfSx7Im5hbWUiOiJCYWNhbGwsIEZpbm4iLCJuYW1lVHlwZSI6IlBlcnNvbmFsIiwiZ2l2ZW5OYW1lIjoiRmlubiIsImZhbWlseU5hbWUiOiJCYWNhbGwiLCJhZmZpbGlhdGlvbiI6WyJUaGUgVW5pdmVyc2l0eSBvZiBNYW5jaGVzdGVyIl0sIm5hbWVJZGVudGlmaWVycyI6W3sibmFtZUlkZW50aWZpZXIiOiIwMDAwLTAwMDItMDA0OC0zMzAwIiwibmFtZUlkZW50aWZpZXJTY2hlbWUiOiJPUkNJRCJ9XX0seyJuYW1lIjoiR29ibGUsIENhcm9sZSIsIm5hbWVUeXBlIjoiUGVyc29uYWwiLCJnaXZlbk5hbWUiOiJDYXJvbGUiLCJmYW1pbHlOYW1lIjoiR29ibGUiLCJhZmZpbGlhdGlvbiI6WyJUaGUgVW5pdmVyc2l0eSBvZiBNYW5jaGVzdGVyIl0sIm5hbWVJZGVudGlmaWVycyI6W3sibmFtZUlkZW50aWZpZXIiOiIwMDAwLTAwMDMtMTIxOS0yMTM3IiwibmFtZUlkZW50aWZpZXJTY2hlbWUiOiJPUkNJRCJ9XX0seyJuYW1lIjoiTcO8bGxlciwgV29sZmdhbmciLCJuYW1lVHlwZSI6IlBlcnNvbmFsIiwiZ2l2ZW5OYW1lIjoiV29sZmdhbmciLCJmYW1pbHlOYW1lIjoiTcO8bGxlciIsImFmZmlsaWF0aW9uIjpbIkhlaWRlbGJlcmcgSW5zdGl0dXRlIGZvciBUaGVvcmV0aWNhbCBTdHVkaWVzIChISVRTKSwgSGVpZGVsYmVyZyJdLCJuYW1lSWRlbnRpZmllcnMiOlt7Im5hbWVJZGVudGlmaWVyIjoiMDAwMC0wMDAyLTQ5ODAtMzUxMiIsIm5hbWVJZGVudGlmaWVyU2NoZW1lIjoiT1JDSUQifV19LHsibmFtZSI6IkdvbGViaWV3c2tpLCBNYXJ0aW4iLCJuYW1lVHlwZSI6IlBlcnNvbmFsIiwiZ2l2ZW5OYW1lIjoiTWFydGluIiwiZmFtaWx5TmFtZSI6IkdvbGViaWV3c2tpIiwiYWZmaWxpYXRpb24iOlsiSGVpZGVsYmVyZyBJbnN0aXR1dGUgZm9yIFRoZW9yZXRpY2FsIFN0dWRpZXMgKEhJVFMpLCBIZWlkZWxiZXJnIl0sIm5hbWVJZGVudGlmaWVycyI6W3sibmFtZUlkZW50aWZpZXIiOiIwMDAwLTAwMDItODY4My03MDg0IiwibmFtZUlkZW50aWZpZXJTY2hlbWUiOiJPUkNJRCJ9XX1dLCJ0aXRsZXMiOlt7InRpdGxlIjoiRmxleGlibGUgTWV0YWRhdGEgU3RydWN0dXJpbmcgZm9yIFJlc2VhcmNoIERhdGEgTWFuYWdlbWVudCBUaHJvdWdoIHRoZSBGQUlSRE9NLVNFRUsgUGxhdGZvcm0gLSBJbXBsZW1lbnRpbmcgVGFpbG9yZWQgYW5kIENvbXBsZXggTWV0YWRhdGEgU2NoZW1lcyBpbiBTRUVLIn1dLCJwdWJsaXNoZXIiOiJaZW5vZG8iLCJjb250YWluZXIiOnt9LCJwdWJsaWNhdGlvblllYXIiOjIwMjUsInN1YmplY3RzIjpbeyJzdWJqZWN0IjoiRkFJUiBkYXRhIn0seyJzdWJqZWN0IjoibWV0YWRhdGEgc2NoZW1hIn0seyJzdWJqZWN0IjoicmVzZWFyY2ggZGF0YSBtYW5hZ2VtZW50In0seyJzdWJqZWN0IjoiRkFJUkRPTS1TRUVLIn0seyJzdWJqZWN0IjoiTkZESTRIZWFsdGgifV0sImNvbnRyaWJ1dG9ycyI6W3sibmFtZSI6IlN1cmUtVmV0dGVyLCBZb3JrIiwibmFtZVR5cGUiOiJQZXJzb25hbCIsImdpdmVuTmFtZSI6IllvcmsiLCJmYW1pbHlOYW1lIjoiU3VyZS1WZXR0ZXIiLCJhZmZpbGlhdGlvbiI6WyJOYXRpb25hbGUgRm9yc2NodW5nc2RhdGVuaW5mcmFzdHJ1a3R1ciAoTkZESSkgZS5WLiJdLCJjb250cmlidXRvclR5cGUiOiJFZGl0b3IiLCJuYW1lSWRlbnRpZmllcnMiOlt7Im5hbWVJZGVudGlmaWVyIjoiMDAwMC0wMDAyLTQ1MjItMTA5OSIsIm5hbWVJZGVudGlmaWVyU2NoZW1lIjoiT1JDSUQifV19LHsibmFtZSI6Ikdyb3RoLCBQYXVsIiwibmFtZVR5cGUiOiJQZXJzb25hbCIsImdpdmVuTmFtZSI6IlBhdWwiLCJmYW1pbHlOYW1lIjoiR3JvdGgiLCJhZmZpbGlhdGlvbiI6WyJVbml2ZXJzaXR5IG9mIEFtc3RlcmRhbSJdLCJjb250cmlidXRvclR5cGUiOiJFZGl0b3IiLCJuYW1lSWRlbnRpZmllcnMiOlt7Im5hbWVJZGVudGlmaWVyIjoiMDAwMC0wMDAzLTAxODMtNjkxMCIsIm5hbWVJZGVudGlmaWVyU2NoZW1lIjoiT1JDSUQifV19XSwiZGF0ZXMiOlt7ImRhdGUiOiIyMDI1LTA4LTA0IiwiZGF0ZVR5cGUiOiJJc3N1ZWQifV0sImxhbmd1YWdlIjpudWxsLCJ0eXBlcyI6eyJyaXMiOiJDUEFQRVIiLCJiaWJ0ZXgiOiJhcnRpY2xlIiwiY2l0ZXByb2MiOiIiLCJzY2hlbWFPcmciOiJBcnRpY2xlIiwicmVzb3VyY2VUeXBlIjoiIiwicmVzb3VyY2VUeXBlR2VuZXJhbCI6IkNvbmZlcmVuY2VQYXBlciJ9LCJyZWxhdGVkSWRlbnRpZmllcnMiOlt7InJlbGF0aW9uVHlwZSI6IklzVmVyc2lvbk9mIiwicmVsYXRlZElkZW50aWZpZXIiOiIxMC41MjgxL3plbm9kby4xNjczNjMyMSIsInJlbGF0ZWRJZGVudGlmaWVyVHlwZSI6IkRPSSJ9XSwicmVsYXRlZEl0ZW1zIjpbXSwic2l6ZXMiOltdLCJmb3JtYXRzIjpbXSwidmVyc2lvbiI6bnVsbCwicmlnaHRzTGlzdCI6W3sicmlnaHRzIjoiQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbiA0LjAgSW50ZXJuYXRpb25hbCIsInJpZ2h0c1VyaSI6Imh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS80LjAvbGVnYWxjb2RlIiwic2NoZW1lVXJpIjoiaHR0cHM6Ly9zcGR4Lm9yZy9saWNlbnNlcy8iLCJyaWdodHNJZGVudGlmaWVyIjoiY2MtYnktNC4wIiwicmlnaHRzSWRlbnRpZmllclNjaGVtZSI6IlNQRFgifV0sImRlc2NyaXB0aW9ucyI6W3siZGVzY3JpcHRpb24iOiJNb2Rlcm4gcmVzZWFyY2ggcHJvamVjdHMgaW5jcmVhc2luZ2x5IHJlcXVpcmUgaHlicmlkIG1ldGFkYXRhIGFwcHJvYWNoZXMgdGhhdCBiYWxhbmNlIGFkaGVyZW5jZSB0byBkb21haW4tb3ZlcmFyY2hpbmcsIGFzIHdlbGwgYXMgZG9tYWluLXNwZWNpZmljIGNvbW11bml0eSBzdGFuZGFyZHMgd2l0aCBmbGV4aWJpbGl0eSBmb3IgcHJvamVjdC0gb3IgcmVzb3VyY2Utc3BlY2lmaWMgbWV0YWRhdGEuIFRoZSBGQUlSRE9NLVNFRUsgcGxhdGZvcm0gWzFdIGlzIGEgd2lkZWx5IHVzZWQgcmVzZWFyY2ggZGF0YSBtYW5hZ2VtZW50IHN5c3RlbSBkZXNpZ25lZCB0byBzdXBwb3J0IGRpdmVyc2UgZG9tYWlucywgZnJvbSBzeXN0ZW1zIGJpb2xvZ3kgdG8gaGVhbHRoIHJlc2VhcmNoIGRhdGEsIGJ5IGludGVncmF0aW5nIHN0YW5kYXJkaXplZCBtZXRhZGF0YSBtb2RlbHMgKGUuZy4sIHRoZSBJU0EgZnJhbWV3b3JrIFsyXSkgd2l0aCBjdXN0b21pemFibGUgZXh0ZW5zaW9ucy4gVG8gYWRkcmVzcyB0aGlzIG5lZWQsIHdlIGludHJvZHVjZSB0aGUgRXh0ZW5kZWQgTWV0YWRhdGEgZmVhdHVyZSBpbiBTRUVLLCB3aGljaCBhbGxvd3MgcmVzZWFyY2hlcnMgdG8gZXh0ZW5kIGNvcmUgbWV0YWRhdGEgc2NoZW1hcyB3aXRoIHVzZXItZGVmaW5lZCBmaWVsZHMsIGhpZXJhcmNoaWVzLCBhbmQgc2VtYW50aWMgYW5ub3RhdGlvbnMgd2hpbGUgZW5zdXJpbmcgaW50ZXJvcGVyYWJpbGl0eSB3aXRoIGRvbWFpbi1zcGVjaWZpYyBzdGFuZGFyZHMuIFdlIGRlbW9uc3RyYXRlIHRoaXMgY2FwYWJpbGl0eSB0aHJvdWdoIHR3byB1c2UgY2FzZXM6ICAxLiBORkRJNEhlYWx0aCBMb2NhbCBEYXRhIEh1YnMgKExESCkgWzNdLFs0XTogSW4gdGhlIGNvbnRleHQgb2YgdGhlIEdlcm1hbiBOYXRpb25hbCBSZXNlYXJjaCBEYXRhIEluZnJhc3RydWN0dXJlIGZvciBQZXJzb25hbCBIZWFsdGggRGF0YSAoTkZESTRIZWFsdGggWzVdKSwgd2UgaGF2ZSBkZXZlbG9wZWQgTG9jYWwgRGF0YSBIdWJzIChMREgpIGJhc2VkIG9uIHRoZSBTRUVLIHBsYXRmb3JtLiBUaGVzZSBodWJzIHN1cHBvcnQgZmVkZXJhdGVkIGRhdGEgc3RydWN0dXJpbmcgYW5kIHNoYXJpbmcgZm9yIHNlbnNpdGl2ZSBoZWFsdGggZGF0YSBmcm9tIGNsaW5pY2FsIHRyaWFscywgZXBpZGVtaW9sb2dpY2FsIHN0dWRpZXMsIGFuZCBwdWJsaWMgaGVhbHRoIHJlc2VhcmNoIGFuZCBhbGxvdyB0byBjb25uZWN0IGxvY2FsIHBsYXRmb3JtcyB0byB0aGUgY2VudHJhbCBtZXRhZGF0YSByZXBvc2l0b3J5IG9mIE5GREk0SGVhbHRoLCB0aGUgR2VybWFuIEhlYWx0aCBTdHVkeSBIdWIuIEdpdmVuIHRoZSBjb21wbGV4aXR5IG9mIHRoZSBORkRJNEhlYWx0aCBtZXRhZGF0YSBzY2hlbWEgKE1EUykgWzZdLCB0aGUgU0VFSy1iYXNlZCBMREggc29mdHdhcmUgdXRpbGl6ZXMgdGhlIEV4dGVuZGVkIE1ldGFkYXRhIGZlYXR1cmUgdG8gZnVsbHkgcmVwcmVzZW50IHRoZSBzY2hlbWEsIGFsbG93aW5nIGZvciBmbGV4aWJsZSBwcm9qZWN0LWRlZmluZWQgbWV0YWRhdGEgZXh0ZW5zaW9ucy4gIDIuIEZBSVIgRGF0YSBTdGF0aW9uIChGQUlSLURTKSBbN106IEJhc2VkIG9uIHRoZSBJU0EtZnJhbWV3b3JrLCB3aXRoIHRoZSBhZGRpdGlvbiBvZiBPYnNlcnZhdGlvbiB1bml0cyBmcm9tIE1JQVBQRSBbOF0sIHRoZSBGQUlSLURTIGlzIGEgd2ViIGFwcGxpY2F0aW9uIHRoYXQgZW5hYmxlcyB1c2VycyB0byBjcmVhdGUgYW5kIG1hbmFnZSBtZXRhZGF0YSBhY2NvcmRpbmcgdG8gRkFJUiBwcmluY2lwbGVzLiBVc2luZyBwYWNrYWdlcyBhbmQgdGVybXMgY29uZmlndXJlZCB0aHJvdWdoIHRoZSBVSSwgaXQgZ2VuZXJhdGVzIEV4Y2VsIHNwcmVhZHNoZWV0cyB3aGljaCBhcmUgdGhlbiBwb3B1bGF0ZWQgdG8gZ2F0aGVyIHRoZSBtZXRhZGF0YS4gRkFJUi1EUyBpcyB0aGVuIHVzZWQgdG8gdmFsaWRhdGUgdGhlIG1ldGFkYXRhIGFuZCBnZW5lcmF0ZXMgUkRGIGRhdGFzZXRzIHJlcHJlc2VudGluZyB0aGUgY29udGVudC4gU0VFSyBoYXMgYmVlbiB1cGRhdGVkIHRvIGFsbG93IEV4dGVuZGVkIE1ldGFkYXRhIGFuZCBTYW1wbGUgVHlwZXMgdG8gYmUgY29uZmlndXJlZCBhdXRvbWF0aWNhbGx5IHZpYSB0aGVzZSBSREYgZGF0YXNldHMsIGFuZCBhbHNvIHRoZSBjb250ZW50IGNhbiBiZSBpbXBvcnRlZCwgYW5kIHVwZGF0ZWQsIGluIGEgc2luZ2xlIGFjdGlvbi4gIFRoZSBFeHRlbmRlZCBNZXRhZGF0YSBmZWF0dXJlIGFsbG93cyB1c2VycyB0byBkZWZpbmUgYWRkaXRpb25hbCBtZXRhZGF0YSBhdHRyaWJ1dGVzIHRvIGJlIHRhaWxvcmVkIHRvIHNwZWNpZmljIGRhdGEgdHlwZXMsIGVuc3VyaW5nIGNvbXBsaWFuY2Ugd2l0aCBzdGFuZGFyZHMuIFdoZW4gY3JlYXRpbmcgYSByZXNvdXJjZSwgdXNlcnMgY2FuIHNlbGVjdCBhbiBFeHRlbmRlZCBNZXRhZGF0YSB0eXBlIGZyb20gYSBkcm9wZG93biBtZW51LCBkeW5hbWljYWxseSB0cmlnZ2VyaW5nIHRoZSByZW5kZXJpbmcgb2YgYXNzb2NpYXRlZCBtZXRhZGF0YSBpbnB1dCBmb3JtcyB3aXRoaW4gdGhlIHdlYiBpbnRlcmZhY2UuIFRoaXMgZW5hYmxlcyBzZWFtbGVzcyBpbnRlZ3JhdGlvbiBvZiByZXNvdXJjZS1zcGVjaWZpYyBtZXRhZGF0YSAoZS5nLiwgY2xpbmljYWwgdHJpYWwgc3R1ZHkgbWV0YWRhdGEpIGFsb25nc2lkZSBjb3JlIGRlc2NyaXB0aXZlIGZpZWxkcy4gIEN1cnJlbnRseSwgb25seSBpbnN0YW5jZSBhZG1pbmlzdHJhdG9ycyBjYW4gY3JlYXRlLCBtYW5hZ2UgKGVuYWJsZS9kaXNhYmxlKSwgYW5kIGRlbGV0ZSBhZGRpdGlvbmFsIGF0dHJpYnV0ZXMgZm9yIHNwZWNpZmljIHJlc291cmNlIHR5cGVzIChlLmcuLCBJU0EgaXRlbXMgc3VjaCBhcyBJbnZlc3RpZ2F0aW9uLCBTdHVkeSwgQXNzYXksIGFzIHdlbGwgYXMgUHJvamVjdHMgYW5kIE1vZGVscykgYmFzZWQgb24gc3BlY2lmaWMgc2NoZW1hcyAoZS5nLiwgdGhlIE5GREk0SGVhbHRoIE1EUykuIEF0dHJpYnV0ZSB0eXBlcyByYW5nZSBmcm9tIHNpbXBsZSAoZS5nLiwgc3RyaW5nLCB0ZXh0LCBkYXRlLCBpbnRlZ2VyLCBCb29sZWFuKSB0byBjb21wbGV4IChlLmcuLCBjb250cm9sbGVkIHZvY2FidWxhcmllcyBsaW5rZWQgdG8gb250b2xvZ2llcywgbmVzdGVkIGhpZXJhcmNoaWNhbCBzdHJ1Y3R1cmVzKSwgd2l0aCB2YWxpZGF0aW9uIHJ1bGVzIGZvciBtYW5kYXRvcnkgb3Igb3B0aW9uYWwgZmllbGRzLiBSZWd1bGFyIGV4cHJlc3Npb25zIGFyZSBpbnRyb2R1Y2VkIHRvIGVuc3VyZSBjb3JyZWN0IGlucHV0IGZvcm1hdHRpbmcuICBNZXRhZGF0YSBzY2hlbWFzIGNhbiBiZSBjcmVhdGVkIHRocm91Z2ggYmFja2VuZCBzZWVkIGZpbGVzLCBKU09OIHVwbG9hZHMsIG9yIEZBSVItRFMgUkRGIGltcG9ydHMuIFRoZXNlIHNjaGVtYXMgYXJlIHByb2dyYW1tYXRpY2FsbHkgYWNjZXNzaWJsZSB2aWEgdGhlIFNFRUsgUkVTVCBBUEksIGVuYWJsaW5nIGF1dG9tYXRlZCBtZXRhZGF0YSBjcmVhdGlvbiBhbmQgcmV0cmlldmFsLiBUaGlzIGVuc3VyZXMgaW50ZXJvcGVyYWJpbGl0eSB3aXRoIGV4dGVybmFsIHRvb2xzIHdoaWxlIGFkaGVyaW5nIHRvIEZBSVIgZGF0YSBwcmluY2lwbGVzLiIsImRlc2NyaXB0aW9uVHlwZSI6IkFic3RyYWN0In1dLCJnZW9Mb2NhdGlvbnMiOltdLCJmdW5kaW5nUmVmZXJlbmNlcyI6W10sInhtbCI6IlBEOTRiV3dnZG1WeWMybHZiajBpTVM0d0lpQmxibU52WkdsdVp6MGlWVlJHTFRnaVB6NEtQSEpsYzI5MWNtTmxJSGh0Ykc1ek9uaHphVDBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01TOVlUVXhUWTJobGJXRXRhVzV6ZEdGdVkyVWlJSGh0Ykc1elBTSm9kSFJ3T2k4dlpHRjBZV05wZEdVdWIzSm5MM05qYUdWdFlTOXJaWEp1Wld3dE5DSWdlSE5wT25OamFHVnRZVXh2WTJGMGFXOXVQU0pvZEhSd09pOHZaR0YwWVdOcGRHVXViM0puTDNOamFHVnRZUzlyWlhKdVpXd3ROQ0JvZEhSd09pOHZjMk5vWlcxaExtUmhkR0ZqYVhSbExtOXlaeTl0WlhSaEwydGxjbTVsYkMwMEwyMWxkR0ZrWVhSaExuaHpaQ0krQ2lBZ1BHbGtaVzUwYVdacFpYSWdhV1JsYm5ScFptbGxjbFI1Y0dVOUlrUlBTU0krTVRBdU5USTRNUzlhUlU1UFJFOHVNVFkzTXpZek1qSThMMmxrWlc1MGFXWnBaWEkrQ2lBZ1BHTnlaV0YwYjNKelBnb2dJQ0FnUEdOeVpXRjBiM0krQ2lBZ0lDQWdJRHhqY21WaGRHOXlUbUZ0WlNCdVlXMWxWSGx3WlQwaVVHVnljMjl1WVd3aVBraDFMQ0JZYVdGdmJXbHVaend2WTNKbFlYUnZjazVoYldVK0NpQWdJQ0FnSUR4bmFYWmxiazVoYldVK1dHbGhiMjFwYm1jOEwyZHBkbVZ1VG1GdFpUNEtJQ0FnSUNBZ1BHWmhiV2xzZVU1aGJXVStTSFU4TDJaaGJXbHNlVTVoYldVK0NpQWdJQ0FnSUR4dVlXMWxTV1JsYm5ScFptbGxjaUJ1WVcxbFNXUmxiblJwWm1sbGNsTmphR1Z0WlQwaVQxSkRTVVFpSUhOamFHVnRaVlZTU1QwaUlqNHdNREF3TFRBd01ESXRPRE14T0Mwek1qSXlQQzl1WVcxbFNXUmxiblJwWm1sbGNqNEtJQ0FnSUNBZ1BHRm1abWxzYVdGMGFXOXVQa2hsYVdSbGJHSmxjbWNnU1c1emRHbDBkWFJsSUdadmNpQlVhR1Z2Y21WMGFXTmhiQ0JUZEhWa2FXVnpJQ2hJU1ZSVEtTd2dTR1ZwWkdWc1ltVnlaend2WVdabWFXeHBZWFJwYjI0K0NpQWdJQ0E4TDJOeVpXRjBiM0krQ2lBZ0lDQThZM0psWVhSdmNqNEtJQ0FnSUNBZ1BHTnlaV0YwYjNKT1lXMWxJRzVoYldWVWVYQmxQU0pRWlhKemIyNWhiQ0krVDNkbGJpd2dVM1IxWVhKMFBDOWpjbVZoZEc5eVRtRnRaVDRLSUNBZ0lDQWdQR2RwZG1WdVRtRnRaVDVUZEhWaGNuUThMMmRwZG1WdVRtRnRaVDRLSUNBZ0lDQWdQR1poYldsc2VVNWhiV1UrVDNkbGJqd3ZabUZ0YVd4NVRtRnRaVDRLSUNBZ0lDQWdQRzVoYldWSlpHVnVkR2xtYVdWeUlHNWhiV1ZKWkdWdWRHbG1hV1Z5VTJOb1pXMWxQU0pQVWtOSlJDSWdjMk5vWlcxbFZWSkpQU0lpUGpBd01EQXRNREF3TXkweU1UTXdMVEE0TmpVOEwyNWhiV1ZKWkdWdWRHbG1hV1Z5UGdvZ0lDQWdJQ0E4WVdabWFXeHBZWFJwYjI0K1ZHaGxJRlZ1YVhabGNuTnBkSGtnYjJZZ1RXRnVZMmhsYzNSbGNqd3ZZV1ptYVd4cFlYUnBiMjQrQ2lBZ0lDQThMMk55WldGMGIzSStDaUFnSUNBOFkzSmxZWFJ2Y2o0S0lDQWdJQ0FnUEdOeVpXRjBiM0pPWVcxbElHNWhiV1ZVZVhCbFBTSlFaWEp6YjI1aGJDSStUV1ZwYm1WclpTd2dSbkpoYm1zOEwyTnlaV0YwYjNKT1lXMWxQZ29nSUNBZ0lDQThaMmwyWlc1T1lXMWxQa1p5WVc1clBDOW5hWFpsYms1aGJXVStDaUFnSUNBZ0lEeG1ZVzFwYkhsT1lXMWxQazFsYVc1bGEyVThMMlpoYldsc2VVNWhiV1UrQ2lBZ0lDQWdJRHh1WVcxbFNXUmxiblJwWm1sbGNpQnVZVzFsU1dSbGJuUnBabWxsY2xOamFHVnRaVDBpVDFKRFNVUWlJSE5qYUdWdFpWVlNTVDBpSWo0d01EQXdMVEF3TURJdE9USTFOaTAzTlRRelBDOXVZVzFsU1dSbGJuUnBabWxsY2o0S0lDQWdJQ0FnUEdGbVptbHNhV0YwYVc5dVBsVnVhWFpsY25OcGRNT2tkQ0JNWldsd2VtbG5MQ0JKVFVsVFJUd3ZZV1ptYVd4cFlYUnBiMjQrQ2lBZ0lDQThMMk55WldGMGIzSStDaUFnSUNBOFkzSmxZWFJ2Y2o0S0lDQWdJQ0FnUEdOeVpXRjBiM0pPWVcxbElHNWhiV1ZVZVhCbFBTSlFaWEp6YjI1aGJDSStRbUZqWVd4c0xDQkdhVzV1UEM5amNtVmhkRzl5VG1GdFpUNEtJQ0FnSUNBZ1BHZHBkbVZ1VG1GdFpUNUdhVzV1UEM5bmFYWmxiazVoYldVK0NpQWdJQ0FnSUR4bVlXMXBiSGxPWVcxbFBrSmhZMkZzYkR3dlptRnRhV3g1VG1GdFpUNEtJQ0FnSUNBZ1BHNWhiV1ZKWkdWdWRHbG1hV1Z5SUc1aGJXVkpaR1Z1ZEdsbWFXVnlVMk5vWlcxbFBTSlBVa05KUkNJZ2MyTm9aVzFsVlZKSlBTSWlQakF3TURBdE1EQXdNaTB3TURRNExUTXpNREE4TDI1aGJXVkpaR1Z1ZEdsbWFXVnlQZ29nSUNBZ0lDQThZV1ptYVd4cFlYUnBiMjQrVkdobElGVnVhWFpsY25OcGRIa2diMllnVFdGdVkyaGxjM1JsY2p3dllXWm1hV3hwWVhScGIyNCtDaUFnSUNBOEwyTnlaV0YwYjNJK0NpQWdJQ0E4WTNKbFlYUnZjajRLSUNBZ0lDQWdQR055WldGMGIzSk9ZVzFsSUc1aGJXVlVlWEJsUFNKUVpYSnpiMjVoYkNJK1IyOWliR1VzSUVOaGNtOXNaVHd2WTNKbFlYUnZjazVoYldVK0NpQWdJQ0FnSUR4bmFYWmxiazVoYldVK1EyRnliMnhsUEM5bmFYWmxiazVoYldVK0NpQWdJQ0FnSUR4bVlXMXBiSGxPWVcxbFBrZHZZbXhsUEM5bVlXMXBiSGxPWVcxbFBnb2dJQ0FnSUNBOGJtRnRaVWxrWlc1MGFXWnBaWElnYm1GdFpVbGtaVzUwYVdacFpYSlRZMmhsYldVOUlrOVNRMGxFSWlCelkyaGxiV1ZWVWtrOUlpSStNREF3TUMwd01EQXpMVEV5TVRrdE1qRXpOend2Ym1GdFpVbGtaVzUwYVdacFpYSStDaUFnSUNBZ0lEeGhabVpwYkdsaGRHbHZiajVVYUdVZ1ZXNXBkbVZ5YzJsMGVTQnZaaUJOWVc1amFHVnpkR1Z5UEM5aFptWnBiR2xoZEdsdmJqNEtJQ0FnSUR3dlkzSmxZWFJ2Y2o0S0lDQWdJRHhqY21WaGRHOXlQZ29nSUNBZ0lDQThZM0psWVhSdmNrNWhiV1VnYm1GdFpWUjVjR1U5SWxCbGNuTnZibUZzSWo1Tnc3eHNiR1Z5TENCWGIyeG1aMkZ1Wnp3dlkzSmxZWFJ2Y2s1aGJXVStDaUFnSUNBZ0lEeG5hWFpsYms1aGJXVStWMjlzWm1kaGJtYzhMMmRwZG1WdVRtRnRaVDRLSUNBZ0lDQWdQR1poYldsc2VVNWhiV1UrVGNPOGJHeGxjand2Wm1GdGFXeDVUbUZ0WlQ0S0lDQWdJQ0FnUEc1aGJXVkpaR1Z1ZEdsbWFXVnlJRzVoYldWSlpHVnVkR2xtYVdWeVUyTm9aVzFsUFNKUFVrTkpSQ0lnYzJOb1pXMWxWVkpKUFNJaVBqQXdNREF0TURBd01pMDBPVGd3TFRNMU1USThMMjVoYldWSlpHVnVkR2xtYVdWeVBnb2dJQ0FnSUNBOFlXWm1hV3hwWVhScGIyNCtTR1ZwWkdWc1ltVnlaeUJKYm5OMGFYUjFkR1VnWm05eUlGUm9aVzl5WlhScFkyRnNJRk4wZFdScFpYTWdLRWhKVkZNcExDQklaV2xrWld4aVpYSm5QQzloWm1acGJHbGhkR2x2Ymo0S0lDQWdJRHd2WTNKbFlYUnZjajRLSUNBZ0lEeGpjbVZoZEc5eVBnb2dJQ0FnSUNBOFkzSmxZWFJ2Y2s1aGJXVWdibUZ0WlZSNWNHVTlJbEJsY25OdmJtRnNJajVIYjJ4bFltbGxkM05yYVN3Z1RXRnlkR2x1UEM5amNtVmhkRzl5VG1GdFpUNEtJQ0FnSUNBZ1BHZHBkbVZ1VG1GdFpUNU5ZWEowYVc0OEwyZHBkbVZ1VG1GdFpUNEtJQ0FnSUNBZ1BHWmhiV2xzZVU1aGJXVStSMjlzWldKcFpYZHphMms4TDJaaGJXbHNlVTVoYldVK0NpQWdJQ0FnSUR4dVlXMWxTV1JsYm5ScFptbGxjaUJ1WVcxbFNXUmxiblJwWm1sbGNsTmphR1Z0WlQwaVQxSkRTVVFpSUhOamFHVnRaVlZTU1QwaUlqNHdNREF3TFRBd01ESXRPRFk0TXkwM01EZzBQQzl1WVcxbFNXUmxiblJwWm1sbGNqNEtJQ0FnSUNBZ1BHRm1abWxzYVdGMGFXOXVQa2hsYVdSbGJHSmxjbWNnU1c1emRHbDBkWFJsSUdadmNpQlVhR1Z2Y21WMGFXTmhiQ0JUZEhWa2FXVnpJQ2hJU1ZSVEtTd2dTR1ZwWkdWc1ltVnlaend2WVdabWFXeHBZWFJwYjI0K0NpQWdJQ0E4TDJOeVpXRjBiM0krQ2lBZ1BDOWpjbVZoZEc5eWN6NEtJQ0E4ZEdsMGJHVnpQZ29nSUNBZ1BIUnBkR3hsUGtac1pYaHBZbXhsSUUxbGRHRmtZWFJoSUZOMGNuVmpkSFZ5YVc1bklHWnZjaUJTWlhObFlYSmphQ0JFWVhSaElFMWhibUZuWlcxbGJuUWdWR2h5YjNWbmFDQjBhR1VnUmtGSlVrUlBUUzFUUlVWTElGQnNZWFJtYjNKdElDMGdTVzF3YkdWdFpXNTBhVzVuSUZSaGFXeHZjbVZrSUdGdVpDQkRiMjF3YkdWNElFMWxkR0ZrWVhSaElGTmphR1Z0WlhNZ2FXNGdVMFZGU3p3dmRHbDBiR1UrQ2lBZ1BDOTBhWFJzWlhNK0NpQWdQSEIxWW14cGMyaGxjajVhWlc1dlpHODhMM0IxWW14cGMyaGxjajRLSUNBOGNIVmliR2xqWVhScGIyNVpaV0Z5UGpJd01qVThMM0IxWW14cFkyRjBhVzl1V1dWaGNqNEtJQ0E4Y21WemIzVnlZMlZVZVhCbElISmxjMjkxY21ObFZIbHdaVWRsYm1WeVlXdzlJa052Ym1abGNtVnVZMlZRWVhCbGNpSXZQZ29nSUR4emRXSnFaV04wY3o0S0lDQWdJRHh6ZFdKcVpXTjBQa1pCU1ZJZ1pHRjBZVHd2YzNWaWFtVmpkRDRLSUNBZ0lEeHpkV0pxWldOMFBtMWxkR0ZrWVhSaElITmphR1Z0WVR3dmMzVmlhbVZqZEQ0S0lDQWdJRHh6ZFdKcVpXTjBQbkpsYzJWaGNtTm9JR1JoZEdFZ2JXRnVZV2RsYldWdWREd3ZjM1ZpYW1WamRENEtJQ0FnSUR4emRXSnFaV04wUGtaQlNWSkVUMDB0VTBWRlN6d3ZjM1ZpYW1WamRENEtJQ0FnSUR4emRXSnFaV04wUGs1R1JFazBTR1ZoYkhSb1BDOXpkV0pxWldOMFBnb2dJRHd2YzNWaWFtVmpkSE0rQ2lBZ1BHTnZiblJ5YVdKMWRHOXljejRLSUNBZ0lEeGpiMjUwY21saWRYUnZjaUJqYjI1MGNtbGlkWFJ2Y2xSNWNHVTlJa1ZrYVhSdmNpSStDaUFnSUNBZ0lEeGpiMjUwY21saWRYUnZjazVoYldVZ2JtRnRaVlI1Y0dVOUlsQmxjbk52Ym1Gc0lqNVRkWEpsTFZabGRIUmxjaXdnV1c5eWF6d3ZZMjl1ZEhKcFluVjBiM0pPWVcxbFBnb2dJQ0FnSUNBOFoybDJaVzVPWVcxbFBsbHZjbXM4TDJkcGRtVnVUbUZ0WlQ0S0lDQWdJQ0FnUEdaaGJXbHNlVTVoYldVK1UzVnlaUzFXWlhSMFpYSThMMlpoYldsc2VVNWhiV1UrQ2lBZ0lDQWdJRHh1WVcxbFNXUmxiblJwWm1sbGNpQnVZVzFsU1dSbGJuUnBabWxsY2xOamFHVnRaVDBpVDFKRFNVUWlJSE5qYUdWdFpWVlNTVDBpSWo0d01EQXdMVEF3TURJdE5EVXlNaTB4TURrNVBDOXVZVzFsU1dSbGJuUnBabWxsY2o0S0lDQWdJQ0FnUEdGbVptbHNhV0YwYVc5dVBrNWhkR2x2Ym1Gc1pTQkdiM0p6WTJoMWJtZHpaR0YwWlc1cGJtWnlZWE4wY25WcmRIVnlJQ2hPUmtSSktTQmxMbFl1UEM5aFptWnBiR2xoZEdsdmJqNEtJQ0FnSUR3dlkyOXVkSEpwWW5WMGIzSStDaUFnSUNBOFkyOXVkSEpwWW5WMGIzSWdZMjl1ZEhKcFluVjBiM0pVZVhCbFBTSkZaR2wwYjNJaVBnb2dJQ0FnSUNBOFkyOXVkSEpwWW5WMGIzSk9ZVzFsSUc1aGJXVlVlWEJsUFNKUVpYSnpiMjVoYkNJK1IzSnZkR2dzSUZCaGRXdzhMMk52Ym5SeWFXSjFkRzl5VG1GdFpUNEtJQ0FnSUNBZ1BHZHBkbVZ1VG1GdFpUNVFZWFZzUEM5bmFYWmxiazVoYldVK0NpQWdJQ0FnSUR4bVlXMXBiSGxPWVcxbFBrZHliM1JvUEM5bVlXMXBiSGxPWVcxbFBnb2dJQ0FnSUNBOGJtRnRaVWxrWlc1MGFXWnBaWElnYm1GdFpVbGtaVzUwYVdacFpYSlRZMmhsYldVOUlrOVNRMGxFSWlCelkyaGxiV1ZWVWtrOUlpSStNREF3TUMwd01EQXpMVEF4T0RNdE5qa3hNRHd2Ym1GdFpVbGtaVzUwYVdacFpYSStDaUFnSUNBZ0lEeGhabVpwYkdsaGRHbHZiajVWYm1sMlpYSnphWFI1SUc5bUlFRnRjM1JsY21SaGJUd3ZZV1ptYVd4cFlYUnBiMjQrQ2lBZ0lDQThMMk52Ym5SeWFXSjFkRzl5UGdvZ0lEd3ZZMjl1ZEhKcFluVjBiM0p6UGdvZ0lEeGtZWFJsY3o0S0lDQWdJRHhrWVhSbElHUmhkR1ZVZVhCbFBTSkpjM04xWldRaVBqSXdNalV0TURndE1EUThMMlJoZEdVK0NpQWdQQzlrWVhSbGN6NEtJQ0E4WVd4MFpYSnVZWFJsU1dSbGJuUnBabWxsY25NK0NpQWdJQ0E4WVd4MFpYSnVZWFJsU1dSbGJuUnBabWxsY2lCaGJIUmxjbTVoZEdWSlpHVnVkR2xtYVdWeVZIbHdaVDBpYjJGcElqNXZZV2s2ZW1WdWIyUnZMbTl5WnpveE5qY3pOak15TWp3dllXeDBaWEp1WVhSbFNXUmxiblJwWm1sbGNqNEtJQ0E4TDJGc2RHVnlibUYwWlVsa1pXNTBhV1pwWlhKelBnb2dJRHh5Wld4aGRHVmtTV1JsYm5ScFptbGxjbk0rQ2lBZ0lDQThjbVZzWVhSbFpFbGtaVzUwYVdacFpYSWdjbVZzWVhSbFpFbGtaVzUwYVdacFpYSlVlWEJsUFNKRVQwa2lJSEpsYkdGMGFXOXVWSGx3WlQwaVNYTldaWEp6YVc5dVQyWWlQakV3TGpVeU9ERXZlbVZ1YjJSdkxqRTJOek0yTXpJeFBDOXlaV3hoZEdWa1NXUmxiblJwWm1sbGNqNEtJQ0E4TDNKbGJHRjBaV1JKWkdWdWRHbG1hV1Z5Y3o0S0lDQThjMmw2WlhNdlBnb2dJRHhtYjNKdFlYUnpMejRLSUNBOGRtVnljMmx2Ymk4K0NpQWdQSEpwWjJoMGMweHBjM1ErQ2lBZ0lDQThjbWxuYUhSeklISnBaMmgwYzFWU1NUMGlhSFIwY0hNNkx5OWpjbVZoZEdsMlpXTnZiVzF2Ym5NdWIzSm5MMnhwWTJWdWMyVnpMMko1THpRdU1DOXNaV2RoYkdOdlpHVWlJSEpwWjJoMGMwbGtaVzUwYVdacFpYSTlJbU5qTFdKNUxUUXVNQ0lnY21sbmFIUnpTV1JsYm5ScFptbGxjbE5qYUdWdFpUMGljM0JrZUNJK1EzSmxZWFJwZG1VZ1EyOXRiVzl1Y3lCQmRIUnlhV0oxZEdsdmJpQTBMakFnU1c1MFpYSnVZWFJwYjI1aGJEd3ZjbWxuYUhSelBnb2dJRHd2Y21sbmFIUnpUR2x6ZEQ0S0lDQThaR1Z6WTNKcGNIUnBiMjV6UGdvZ0lDQWdQR1JsYzJOeWFYQjBhVzl1SUdSbGMyTnlhWEIwYVc5dVZIbHdaVDBpUVdKemRISmhZM1FpUGsxdlpHVnliaUJ5WlhObFlYSmphQ0J3Y205cVpXTjBjeUJwYm1OeVpXRnphVzVuYkhrZ2NtVnhkV2x5WlNCb2VXSnlhV1FnYldWMFlXUmhkR0VnWVhCd2NtOWhZMmhsY3lCMGFHRjBJR0poYkdGdVkyVWdZV1JvWlhKbGJtTmxJSFJ2SUdSdmJXRnBiaTF2ZG1WeVlYSmphR2x1Wnl3Z1lYTWdkMlZzYkNCaGN5QmtiMjFoYVc0dGMzQmxZMmxtYVdNZ1kyOXRiWFZ1YVhSNUlITjBZVzVrWVhKa2N5QjNhWFJvSUdac1pYaHBZbWxzYVhSNUlHWnZjaUJ3Y205cVpXTjBMU0J2Y2lCeVpYTnZkWEpqWlMxemNHVmphV1pwWXlCdFpYUmhaR0YwWVM0Z1ZHaGxJRVpCU1ZKRVQwMHRVMFZGU3lCd2JHRjBabTl5YlNCYk1WMGdhWE1nWVNCM2FXUmxiSGtnZFhObFpDQnlaWE5sWVhKamFDQmtZWFJoSUcxaGJtRm5aVzFsYm5RZ2MzbHpkR1Z0SUdSbGMybG5ibVZrSUhSdklITjFjSEJ2Y25RZ1pHbDJaWEp6WlNCa2IyMWhhVzV6TENCbWNtOXRJSE41YzNSbGJYTWdZbWx2Ykc5bmVTQjBieUJvWldGc2RHZ2djbVZ6WldGeVkyZ2daR0YwWVN3Z1lua2dhVzUwWldkeVlYUnBibWNnYzNSaGJtUmhjbVJwZW1Wa0lHMWxkR0ZrWVhSaElHMXZaR1ZzY3lBb1pTNW5MaXdnZEdobElFbFRRU0JtY21GdFpYZHZjbXNnV3pKZEtTQjNhWFJvSUdOMWMzUnZiV2w2WVdKc1pTQmxlSFJsYm5OcGIyNXpMaUJVYnlCaFpHUnlaWE56SUhSb2FYTWdibVZsWkN3Z2QyVWdhVzUwY205a2RXTmxJSFJvWlNCRmVIUmxibVJsWkNCTlpYUmhaR0YwWVNCbVpXRjBkWEpsSUdsdUlGTkZSVXNzSUhkb2FXTm9JR0ZzYkc5M2N5QnlaWE5sWVhKamFHVnljeUIwYnlCbGVIUmxibVFnWTI5eVpTQnRaWFJoWkdGMFlTQnpZMmhsYldGeklIZHBkR2dnZFhObGNpMWtaV1pwYm1Wa0lHWnBaV3hrY3l3Z2FHbGxjbUZ5WTJocFpYTXNJR0Z1WkNCelpXMWhiblJwWXlCaGJtNXZkR0YwYVc5dWN5QjNhR2xzWlNCbGJuTjFjbWx1WnlCcGJuUmxjbTl3WlhKaFltbHNhWFI1SUhkcGRHZ2daRzl0WVdsdUxYTndaV05wWm1saklITjBZVzVrWVhKa2N5NGdWMlVnWkdWdGIyNXpkSEpoZEdVZ2RHaHBjeUJqWVhCaFltbHNhWFI1SUhSb2NtOTFaMmdnZEhkdklIVnpaU0JqWVhObGN6b2dJREV1SUU1R1JFazBTR1ZoYkhSb0lFeHZZMkZzSUVSaGRHRWdTSFZpY3lBb1RFUklLU0JiTTEwc1d6UmRPaUJKYmlCMGFHVWdZMjl1ZEdWNGRDQnZaaUIwYUdVZ1IyVnliV0Z1SUU1aGRHbHZibUZzSUZKbGMyVmhjbU5vSUVSaGRHRWdTVzVtY21GemRISjFZM1IxY21VZ1ptOXlJRkJsY25OdmJtRnNJRWhsWVd4MGFDQkVZWFJoSUNoT1JrUkpORWhsWVd4MGFDQmJOVjBwTENCM1pTQm9ZWFpsSUdSbGRtVnNiM0JsWkNCTWIyTmhiQ0JFWVhSaElFaDFZbk1nS0V4RVNDa2dZbUZ6WldRZ2IyNGdkR2hsSUZORlJVc2djR3hoZEdadmNtMHVJRlJvWlhObElHaDFZbk1nYzNWd2NHOXlkQ0JtWldSbGNtRjBaV1FnWkdGMFlTQnpkSEoxWTNSMWNtbHVaeUJoYm1RZ2MyaGhjbWx1WnlCbWIzSWdjMlZ1YzJsMGFYWmxJR2hsWVd4MGFDQmtZWFJoSUdaeWIyMGdZMnhwYm1sallXd2dkSEpwWVd4ekxDQmxjR2xrWlcxcGIyeHZaMmxqWVd3Z2MzUjFaR2xsY3l3Z1lXNWtJSEIxWW14cFl5Qm9aV0ZzZEdnZ2NtVnpaV0Z5WTJnZ1lXNWtJR0ZzYkc5M0lIUnZJR052Ym01bFkzUWdiRzlqWVd3Z2NHeGhkR1p2Y20xeklIUnZJSFJvWlNCalpXNTBjbUZzSUcxbGRHRmtZWFJoSUhKbGNHOXphWFJ2Y25rZ2IyWWdUa1pFU1RSSVpXRnNkR2dzSUhSb1pTQkhaWEp0WVc0Z1NHVmhiSFJvSUZOMGRXUjVJRWgxWWk0Z1IybDJaVzRnZEdobElHTnZiWEJzWlhocGRIa2diMllnZEdobElFNUdSRWswU0dWaGJIUm9JRzFsZEdGa1lYUmhJSE5qYUdWdFlTQW9UVVJUS1NCYk5sMHNJSFJvWlNCVFJVVkxMV0poYzJWa0lFeEVTQ0J6YjJaMGQyRnlaU0IxZEdsc2FYcGxjeUIwYUdVZ1JYaDBaVzVrWldRZ1RXVjBZV1JoZEdFZ1ptVmhkSFZ5WlNCMGJ5Qm1kV3hzZVNCeVpYQnlaWE5sYm5RZ2RHaGxJSE5qYUdWdFlTd2dZV3hzYjNkcGJtY2dabTl5SUdac1pYaHBZbXhsSUhCeWIycGxZM1F0WkdWbWFXNWxaQ0J0WlhSaFpHRjBZU0JsZUhSbGJuTnBiMjV6TGlBZ01pNGdSa0ZKVWlCRVlYUmhJRk4wWVhScGIyNGdLRVpCU1ZJdFJGTXBJRnMzWFRvZ1FtRnpaV1FnYjI0Z2RHaGxJRWxUUVMxbWNtRnRaWGR2Y21zc0lIZHBkR2dnZEdobElHRmtaR2wwYVc5dUlHOW1JRTlpYzJWeWRtRjBhVzl1SUhWdWFYUnpJR1p5YjIwZ1RVbEJVRkJGSUZzNFhTd2dkR2hsSUVaQlNWSXRSRk1nYVhNZ1lTQjNaV0lnWVhCd2JHbGpZWFJwYjI0Z2RHaGhkQ0JsYm1GaWJHVnpJSFZ6WlhKeklIUnZJR055WldGMFpTQmhibVFnYldGdVlXZGxJRzFsZEdGa1lYUmhJR0ZqWTI5eVpHbHVaeUIwYnlCR1FVbFNJSEJ5YVc1amFYQnNaWE11SUZWemFXNW5JSEJoWTJ0aFoyVnpJR0Z1WkNCMFpYSnRjeUJqYjI1bWFXZDFjbVZrSUhSb2NtOTFaMmdnZEdobElGVkpMQ0JwZENCblpXNWxjbUYwWlhNZ1JYaGpaV3dnYzNCeVpXRmtjMmhsWlhSeklIZG9hV05vSUdGeVpTQjBhR1Z1SUhCdmNIVnNZWFJsWkNCMGJ5Qm5ZWFJvWlhJZ2RHaGxJRzFsZEdGa1lYUmhMaUJHUVVsU0xVUlRJR2x6SUhSb1pXNGdkWE5sWkNCMGJ5QjJZV3hwWkdGMFpTQjBhR1VnYldWMFlXUmhkR0VnWVc1a0lHZGxibVZ5WVhSbGN5QlNSRVlnWkdGMFlYTmxkSE1nY21Wd2NtVnpaVzUwYVc1bklIUm9aU0JqYjI1MFpXNTBMaUJUUlVWTElHaGhjeUJpWldWdUlIVndaR0YwWldRZ2RHOGdZV3hzYjNjZ1JYaDBaVzVrWldRZ1RXVjBZV1JoZEdFZ1lXNWtJRk5oYlhCc1pTQlVlWEJsY3lCMGJ5QmlaU0JqYjI1bWFXZDFjbVZrSUdGMWRHOXRZWFJwWTJGc2JIa2dkbWxoSUhSb1pYTmxJRkpFUmlCa1lYUmhjMlYwY3l3Z1lXNWtJR0ZzYzI4Z2RHaGxJR052Ym5SbGJuUWdZMkZ1SUdKbElHbHRjRzl5ZEdWa0xDQmhibVFnZFhCa1lYUmxaQ3dnYVc0Z1lTQnphVzVuYkdVZ1lXTjBhVzl1TGlBZ1ZHaGxJRVY0ZEdWdVpHVmtJRTFsZEdGa1lYUmhJR1psWVhSMWNtVWdZV3hzYjNkeklIVnpaWEp6SUhSdklHUmxabWx1WlNCaFpHUnBkR2x2Ym1Gc0lHMWxkR0ZrWVhSaElHRjBkSEpwWW5WMFpYTWdkRzhnWW1VZ2RHRnBiRzl5WldRZ2RHOGdjM0JsWTJsbWFXTWdaR0YwWVNCMGVYQmxjeXdnWlc1emRYSnBibWNnWTI5dGNHeHBZVzVqWlNCM2FYUm9JSE4wWVc1a1lYSmtjeTRnVjJobGJpQmpjbVZoZEdsdVp5QmhJSEpsYzI5MWNtTmxMQ0IxYzJWeWN5QmpZVzRnYzJWc1pXTjBJR0Z1SUVWNGRHVnVaR1ZrSUUxbGRHRmtZWFJoSUhSNWNHVWdabkp2YlNCaElHUnliM0JrYjNkdUlHMWxiblVzSUdSNWJtRnRhV05oYkd4NUlIUnlhV2RuWlhKcGJtY2dkR2hsSUhKbGJtUmxjbWx1WnlCdlppQmhjM052WTJsaGRHVmtJRzFsZEdGa1lYUmhJR2x1Y0hWMElHWnZjbTF6SUhkcGRHaHBiaUIwYUdVZ2QyVmlJR2x1ZEdWeVptRmpaUzRnVkdocGN5QmxibUZpYkdWeklITmxZVzFzWlhOeklHbHVkR1ZuY21GMGFXOXVJRzltSUhKbGMyOTFjbU5sTFhOd1pXTnBabWxqSUcxbGRHRmtZWFJoSUNobExtY3VMQ0JqYkdsdWFXTmhiQ0IwY21saGJDQnpkSFZrZVNCdFpYUmhaR0YwWVNrZ1lXeHZibWR6YVdSbElHTnZjbVVnWkdWelkzSnBjSFJwZG1VZ1ptbGxiR1J6TGlBZ1EzVnljbVZ1ZEd4NUxDQnZibXg1SUdsdWMzUmhibU5sSUdGa2JXbHVhWE4wY21GMGIzSnpJR05oYmlCamNtVmhkR1VzSUcxaGJtRm5aU0FvWlc1aFlteGxMMlJwYzJGaWJHVXBMQ0JoYm1RZ1pHVnNaWFJsSUdGa1pHbDBhVzl1WVd3Z1lYUjBjbWxpZFhSbGN5Qm1iM0lnYzNCbFkybG1hV01nY21WemIzVnlZMlVnZEhsd1pYTWdLR1V1Wnk0c0lFbFRRU0JwZEdWdGN5QnpkV05vSUdGeklFbHVkbVZ6ZEdsbllYUnBiMjRzSUZOMGRXUjVMQ0JCYzNOaGVTd2dZWE1nZDJWc2JDQmhjeUJRY205cVpXTjBjeUJoYm1RZ1RXOWtaV3h6S1NCaVlYTmxaQ0J2YmlCemNHVmphV1pwWXlCelkyaGxiV0Z6SUNobExtY3VMQ0IwYUdVZ1RrWkVTVFJJWldGc2RHZ2dUVVJUS1M0Z1FYUjBjbWxpZFhSbElIUjVjR1Z6SUhKaGJtZGxJR1p5YjIwZ2MybHRjR3hsSUNobExtY3VMQ0J6ZEhKcGJtY3NJSFJsZUhRc0lHUmhkR1VzSUdsdWRHVm5aWElzSUVKdmIyeGxZVzRwSUhSdklHTnZiWEJzWlhnZ0tHVXVaeTRzSUdOdmJuUnliMnhzWldRZ2RtOWpZV0oxYkdGeWFXVnpJR3hwYm10bFpDQjBieUJ2Ym5SdmJHOW5hV1Z6TENCdVpYTjBaV1FnYUdsbGNtRnlZMmhwWTJGc0lITjBjblZqZEhWeVpYTXBMQ0IzYVhSb0lIWmhiR2xrWVhScGIyNGdjblZzWlhNZ1ptOXlJRzFoYm1SaGRHOXllU0J2Y2lCdmNIUnBiMjVoYkNCbWFXVnNaSE11SUZKbFozVnNZWElnWlhod2NtVnpjMmx2Ym5NZ1lYSmxJR2x1ZEhKdlpIVmpaV1FnZEc4Z1pXNXpkWEpsSUdOdmNuSmxZM1FnYVc1d2RYUWdabTl5YldGMGRHbHVaeTRnSUUxbGRHRmtZWFJoSUhOamFHVnRZWE1nWTJGdUlHSmxJR055WldGMFpXUWdkR2h5YjNWbmFDQmlZV05yWlc1a0lITmxaV1FnWm1sc1pYTXNJRXBUVDA0Z2RYQnNiMkZrY3l3Z2IzSWdSa0ZKVWkxRVV5QlNSRVlnYVcxd2IzSjBjeTRnVkdobGMyVWdjMk5vWlcxaGN5QmhjbVVnY0hKdlozSmhiVzFoZEdsallXeHNlU0JoWTJObGMzTnBZbXhsSUhacFlTQjBhR1VnVTBWRlN5QlNSVk5VSUVGUVNTd2daVzVoWW14cGJtY2dZWFYwYjIxaGRHVmtJRzFsZEdGa1lYUmhJR055WldGMGFXOXVJR0Z1WkNCeVpYUnlhV1YyWVd3dUlGUm9hWE1nWlc1emRYSmxjeUJwYm5SbGNtOXdaWEpoWW1sc2FYUjVJSGRwZEdnZ1pYaDBaWEp1WVd3Z2RHOXZiSE1nZDJocGJHVWdZV1JvWlhKcGJtY2dkRzhnUmtGSlVpQmtZWFJoSUhCeWFXNWphWEJzWlhNdVBDOWtaWE5qY21sd2RHbHZiajRLSUNBOEwyUmxjMk55YVhCMGFXOXVjejRLUEM5eVpYTnZkWEpqWlQ0SyIsInVybCI6Imh0dHBzOi8vemVub2RvLm9yZy9kb2kvMTAuNTI4MS96ZW5vZG8uMTY3MzYzMjIiLCJjb250ZW50VXJsIjpudWxsLCJtZXRhZGF0YVZlcnNpb24iOjAsInNjaGVtYVZlcnNpb24iOiJodHRwOi8vZGF0YWNpdGUub3JnL3NjaGVtYS9rZXJuZWwtNCIsInNvdXJjZSI6ImFwaSIsImlzQWN0aXZlIjp0cnVlLCJzdGF0ZSI6ImZpbmRhYmxlIiwicmVhc29uIjpudWxsLCJ2aWV3Q291bnQiOjAsInZpZXdzT3ZlclRpbWUiOltdLCJkb3dubG9hZENvdW50IjowLCJkb3dubG9hZHNPdmVyVGltZSI6W10sInJlZmVyZW5jZUNvdW50IjowLCJjaXRhdGlvbkNvdW50IjowLCJjaXRhdGlvbnNPdmVyVGltZSI6W10sInBhcnRDb3VudCI6MCwicGFydE9mQ291bnQiOjAsInZlcnNpb25Db3VudCI6MCwidmVyc2lvbk9mQ291bnQiOjEsImNyZWF0ZWQiOiIyMDI1LTA4LTA0VDA4OjIzOjMwLjAwMFoiLCJyZWdpc3RlcmVkIjoiMjAyNS0wOC0wNFQwODoyMzozMC4wMDBaIiwicHVibGlzaGVkIjoiMjAyNSIsInVwZGF0ZWQiOiIyMDI1LTA4LTA0VDA4OjIzOjMwLjAwMFoifSwicmVsYXRpb25zaGlwcyI6eyJjbGllbnQiOnsiZGF0YSI6eyJpZCI6ImNlcm4uemVub2RvIiwidHlwZSI6ImNsaWVudHMifX0sInByb3ZpZGVyIjp7ImRhdGEiOnsiaWQiOiJjZXJuIiwidHlwZSI6InByb3ZpZGVycyJ9fSwibWVkaWEiOnsiZGF0YSI6eyJpZCI6IjEwLjUyODEvemVub2RvLjE2NzM2MzIyIiwidHlwZSI6Im1lZGlhIn19LCJyZWZlcmVuY2VzIjp7ImRhdGEiOltdfSwiY2l0YXRpb25zIjp7ImRhdGEiOltdfSwicGFydHMiOnsiZGF0YSI6W119LCJwYXJ0T2YiOnsiZGF0YSI6W119LCJ2ZXJzaW9ucyI6eyJkYXRhIjpbXX0sInZlcnNpb25PZiI6eyJkYXRhIjpbeyJpZCI6IjEwLjUyODEvemVub2RvLjE2NzM2MzIxIiwidHlwZSI6ImRvaXMifV19fX19 + recorded_at: Thu, 30 Oct 2025 20:16:55 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_datacite_response_2.yml b/test/vcr_cassettes/doi/doi_datacite_response_2.yml new file mode 100644 index 0000000000..5bc4a4cb9c --- /dev/null +++ b/test/vcr_cassettes/doi/doi_datacite_response_2.yml @@ -0,0 +1,163 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.5061/dryad.m62gj + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:56 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=aSthVriKzPB6wqnRNaoVZl8UGdMj%2BhOcyO8Qo7QRkfGjCtwNt2qZt7D%2F0UN3m1ixXtU6LYRWIG8tagUpjYfcOoGjQLqJDG40MTnl56S6eNGwyQ%3D%3D"}]}' + Cf-Ray: + - 996d97de9d74dc6c-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.5061/dryad.m62gj", + "RA": "DataCite" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:56 GMT +- request: + method: get + uri: https://api.datacite.org/dois/10.5061/dryad.m62gj + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.datacite.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:56 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Status: + - 200 OK + X-Anonymous-Consumer: + - 'true' + Cache-Control: + - max-age=0, private, must-revalidate + Vary: + - Accept,Accept-Encoding + Referrer-Policy: + - strict-origin-when-cross-origin + X-Permitted-Cross-Domain-Policies: + - none + X-Xss-Protection: + - '0' + X-Request-Id: + - cb61e2a9-ca38-4a8b-bfb0-203a28bf4d97 + Etag: + - W/"6645c4eb0e115ff6caf37f580a849a26" + X-Frame-Options: + - SAMEORIGIN + X-Runtime: + - '0.104181' + X-Content-Type-Options: + - nosniff + X-Powered-By: + - Phusion Passenger(R) 6.1.0 + Server: + - nginx/1.24.0 + Phusion Passenger(R) 6.1.0 + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Methods: + - GET, POST, PUT, PATCH, DELETE, OPTIONS + Access-Control-Allow-Headers: + - Accept,Access-Control-Allow-Origin,Access-Control-Expose-Headers,Access-Control-Allow-Methods,Access-Control-Allow-Headers,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With + Access-Control-Expose-Headers: + - Authorization + body: + encoding: ASCII-8BIT + string: '{"data":{"id":"10.5061/dryad.m62gj","type":"dois","attributes":{"doi":"10.5061/dryad.m62gj","prefix":"10.5061","suffix":"dryad.m62gj","identifiers":[],"alternateIdentifiers":[],"creators":[{"name":"Woodward, + Craig A.","nameType":"Personal","givenName":"Craig A.","familyName":"Woodward","affiliation":["The + University of Queensland"],"nameIdentifiers":[]},{"name":"Shulmeister, James","nameType":"Personal","givenName":"James","familyName":"Shulmeister","affiliation":["The + University of Queensland"],"nameIdentifiers":[]},{"name":"Larsen, Joshua","nameType":"Personal","givenName":"Joshua","familyName":"Larsen","affiliation":["The + University of Queensland"],"nameIdentifiers":[]},{"name":"Jacobsen, Geraldine + E.","nameType":"Personal","givenName":"Geraldine E.","familyName":"Jacobsen","affiliation":["Australian + Nuclear Science and Technology Organisation"],"nameIdentifiers":[]},{"name":"Zawadzki, + Atun","nameType":"Personal","givenName":"Atun","familyName":"Zawadzki","affiliation":["Australian + Nuclear Science and Technology Organisation"],"nameIdentifiers":[]}],"titles":[{"title":"Data + from: The hydrological legacy of deforestation on global wetlands"}],"publisher":"Dryad","container":{},"publicationYear":2015,"subjects":[{"subject":"Deforestation","schemeUri":"https://github.com/PLOS/plos-thesaurus","subjectScheme":"PLOS + Subject Area Thesaurus"},{"subject":"human"},{"subject":"Anthropogenic"},{"subject":"Holocene"}],"contributors":[],"dates":[{"date":"2014-10-30T02:21:19Z","dateType":"Submitted"},{"date":"2015-10-30T00:00:00Z","dateType":"Issued"},{"date":"2015-10-30T00:00:00Z","dateType":"Available"}],"language":"en","types":{"ris":"DATA","bibtex":"misc","citeproc":"dataset","schemaOrg":"Dataset","resourceType":"dataset","resourceTypeGeneral":"Dataset"},"relatedIdentifiers":[{"relationType":"IsCitedBy","relatedIdentifier":"10.1126/science.1260510","relatedIdentifierType":"DOI"}],"relatedItems":[],"sizes":["653124 + bytes"],"formats":[],"version":"1","rightsList":[{"rights":"Creative Commons + Zero v1.0 Universal","rightsUri":"https://creativecommons.org/publicdomain/zero/1.0/legalcode","schemeUri":"https://spdx.org/licenses/","rightsIdentifier":"cc0-1.0","rightsIdentifierScheme":"SPDX"}],"descriptions":[{"description":"Increased + catchment erosion and nutrient loading are commonly recognized\n impacts of + deforestation on global wetlands. In contrast, an increase in\n water availability + in deforested catchments is well known in modern\n studies but is rarely considered + when evaluating past human impacts. We\n used a Budyko water balance approach, + a meta-analysis of global wetland\n response to deforestation, and paleoecological + studies from Australasia to\n explore this issue. After complete deforestation, + we demonstrated that\n water available to wetlands increases by up to 15% + of annual\n precipitation. This can convert ephemeral swamps to permanent + lakes or\n even create new wetlands. This effect is globally significant, + with 9 to\n 12% of wetlands affected, including 20 to 40% of Ramsar wetlands, + but is\n widely unrecognized because human impact studies rarely test for + it.","descriptionType":"Abstract"},{"description":"Database S1Database S1 + is an Excel spreadsheet that contains data from all\n studies of deforestation + in wetland catchments during the Holocene. These\n are the papers used in + the meta-analysis. All sites examined by each paper\n are listed. This information + was extracted from published, peer-reviewed\n journal articlesDatabase S2Database + S2 contains information on specific\n sites where hydrological changes have + occurred after deforestation.This\n information was extracted from published, + peer-reviewed journal articles\n listed in Database S1Database S3This information + was extracted from\n published, peer-reviewed journal articles. Database S3 + contains\n information relating to the meta-analysis. Database S3 contains\n + information from each site where deforestation and wetland change data is\n + available. Post-deforestation wetland changes are identified including; a\n + change in sedimentation rate, eutrophication or change in hydrology.","descriptionType":"Other"}],"geoLocations":[{"geoLocationPlace":"Global + coverage"}],"fundingReferences":[],"xml":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHJlc291cmNlIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zPSJodHRwOi8vZGF0YWNpdGUub3JnL3NjaGVtYS9rZXJuZWwtNCIgeHNpOnNjaGVtYUxvY2F0aW9uPSJodHRwOi8vZGF0YWNpdGUub3JnL3NjaGVtYS9rZXJuZWwtNCBodHRwOi8vc2NoZW1hLmRhdGFjaXRlLm9yZy9tZXRhL2tlcm5lbC00L21ldGFkYXRhLnhzZCI+CiAgPGlkZW50aWZpZXIgaWRlbnRpZmllclR5cGU9IkRPSSI+MTAuNTA2MS9EUllBRC5NNjJHSjwvaWRlbnRpZmllcj4KICA8Y3JlYXRvcnM+CiAgICA8Y3JlYXRvcj4KICAgICAgPGNyZWF0b3JOYW1lIG5hbWVUeXBlPSJQZXJzb25hbCI+V29vZHdhcmQsIENyYWlnIEEuPC9jcmVhdG9yTmFtZT4KICAgICAgPGFmZmlsaWF0aW9uIGFmZmlsaWF0aW9uSWRlbnRpZmllcj0iaHR0cHM6Ly9yb3Iub3JnLzAwcnF5OTQyMiIgYWZmaWxpYXRpb25JZGVudGlmaWVyU2NoZW1lPSJST1IiIHNjaGVtZVVSST0iaHR0cHM6Ly9yb3Iub3JnIj5UaGUgVW5pdmVyc2l0eSBvZiBRdWVlbnNsYW5kPC9hZmZpbGlhdGlvbj4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5TaHVsbWVpc3RlciwgSmFtZXM8L2NyZWF0b3JOYW1lPgogICAgICA8YWZmaWxpYXRpb24gYWZmaWxpYXRpb25JZGVudGlmaWVyPSJodHRwczovL3Jvci5vcmcvMDBycXk5NDIyIiBhZmZpbGlhdGlvbklkZW50aWZpZXJTY2hlbWU9IlJPUiIgc2NoZW1lVVJJPSJodHRwczovL3Jvci5vcmciPlRoZSBVbml2ZXJzaXR5IG9mIFF1ZWVuc2xhbmQ8L2FmZmlsaWF0aW9uPgogICAgPC9jcmVhdG9yPgogICAgPGNyZWF0b3I+CiAgICAgIDxjcmVhdG9yTmFtZSBuYW1lVHlwZT0iUGVyc29uYWwiPkxhcnNlbiwgSm9zaHVhPC9jcmVhdG9yTmFtZT4KICAgICAgPGFmZmlsaWF0aW9uIGFmZmlsaWF0aW9uSWRlbnRpZmllcj0iaHR0cHM6Ly9yb3Iub3JnLzAwcnF5OTQyMiIgYWZmaWxpYXRpb25JZGVudGlmaWVyU2NoZW1lPSJST1IiIHNjaGVtZVVSST0iaHR0cHM6Ly9yb3Iub3JnIj5UaGUgVW5pdmVyc2l0eSBvZiBRdWVlbnNsYW5kPC9hZmZpbGlhdGlvbj4KICAgIDwvY3JlYXRvcj4KICAgIDxjcmVhdG9yPgogICAgICA8Y3JlYXRvck5hbWUgbmFtZVR5cGU9IlBlcnNvbmFsIj5KYWNvYnNlbiwgR2VyYWxkaW5lIEUuPC9jcmVhdG9yTmFtZT4KICAgICAgPGFmZmlsaWF0aW9uIGFmZmlsaWF0aW9uSWRlbnRpZmllcj0iaHR0cHM6Ly9yb3Iub3JnLzA1ajdmZXAyOCIgYWZmaWxpYXRpb25JZGVudGlmaWVyU2NoZW1lPSJST1IiIHNjaGVtZVVSST0iaHR0cHM6Ly9yb3Iub3JnIj5BdXN0cmFsaWFuIE51Y2xlYXIgU2NpZW5jZSBhbmQgVGVjaG5vbG9neSBPcmdhbmlzYXRpb248L2FmZmlsaWF0aW9uPgogICAgPC9jcmVhdG9yPgogICAgPGNyZWF0b3I+CiAgICAgIDxjcmVhdG9yTmFtZSBuYW1lVHlwZT0iUGVyc29uYWwiPlphd2FkemtpLCBBdHVuPC9jcmVhdG9yTmFtZT4KICAgICAgPGFmZmlsaWF0aW9uIGFmZmlsaWF0aW9uSWRlbnRpZmllcj0iaHR0cHM6Ly9yb3Iub3JnLzA1ajdmZXAyOCIgYWZmaWxpYXRpb25JZGVudGlmaWVyU2NoZW1lPSJST1IiIHNjaGVtZVVSST0iaHR0cHM6Ly9yb3Iub3JnIj5BdXN0cmFsaWFuIE51Y2xlYXIgU2NpZW5jZSBhbmQgVGVjaG5vbG9neSBPcmdhbmlzYXRpb248L2FmZmlsaWF0aW9uPgogICAgPC9jcmVhdG9yPgogIDwvY3JlYXRvcnM+CiAgPHRpdGxlcz4KICAgIDx0aXRsZT5EYXRhIGZyb206IFRoZSBoeWRyb2xvZ2ljYWwgbGVnYWN5IG9mIGRlZm9yZXN0YXRpb24gb24gZ2xvYmFsIHdldGxhbmRzPC90aXRsZT4KICA8L3RpdGxlcz4KICA8cHVibGlzaGVyIHB1Ymxpc2hlcklkZW50aWZpZXI9Imh0dHBzOi8vcm9yLm9yZy8wMHg2aDVuOTUiIHB1Ymxpc2hlcklkZW50aWZpZXJTY2hlbWU9IlJPUiIgc2NoZW1lVVJJPSJodHRwczovL3Jvci5vcmcvIj5EcnlhZDwvcHVibGlzaGVyPgogIDxyZXNvdXJjZVR5cGUgcmVzb3VyY2VUeXBlR2VuZXJhbD0iRGF0YXNldCI+ZGF0YXNldDwvcmVzb3VyY2VUeXBlPgogIDxwdWJsaWNhdGlvblllYXI+MjAxNTwvcHVibGljYXRpb25ZZWFyPgogIDxzdWJqZWN0cz4KICAgIDxzdWJqZWN0IHN1YmplY3RTY2hlbWU9IlBMT1MgU3ViamVjdCBBcmVhIFRoZXNhdXJ1cyIgc2NoZW1lVVJJPSJodHRwczovL2dpdGh1Yi5jb20vUExPUy9wbG9zLXRoZXNhdXJ1cyI+RGVmb3Jlc3RhdGlvbjwvc3ViamVjdD4KICAgIDxzdWJqZWN0Pmh1bWFuPC9zdWJqZWN0PgogICAgPHN1YmplY3Q+QW50aHJvcG9nZW5pYzwvc3ViamVjdD4KICAgIDxzdWJqZWN0PkhvbG9jZW5lPC9zdWJqZWN0PgogIDwvc3ViamVjdHM+CiAgPGRhdGVzPgogICAgPGRhdGUgZGF0ZVR5cGU9IlN1Ym1pdHRlZCI+MjAxNC0xMC0zMFQwMjoyMToxOVo8L2RhdGU+CiAgICA8ZGF0ZSBkYXRlVHlwZT0iSXNzdWVkIj4yMDE1LTEwLTMwVDAwOjAwOjAwWjwvZGF0ZT4KICAgIDxkYXRlIGRhdGVUeXBlPSJBdmFpbGFibGUiPjIwMTUtMTAtMzBUMDA6MDA6MDBaPC9kYXRlPgogIDwvZGF0ZXM+CiAgPGxhbmd1YWdlPmVuPC9sYW5ndWFnZT4KICA8cmVsYXRlZElkZW50aWZpZXJzPgogICAgPHJlbGF0ZWRJZGVudGlmaWVyIHJlbGF0aW9uVHlwZT0iSXNDaXRlZEJ5IiByZWxhdGVkSWRlbnRpZmllclR5cGU9IkRPSSI+aHR0cHM6Ly9kb2kub3JnLzEwLjExMjYvc2NpZW5jZS4xMjYwNTEwPC9yZWxhdGVkSWRlbnRpZmllcj4KICA8L3JlbGF0ZWRJZGVudGlmaWVycz4KICA8c2l6ZXM+CiAgICA8c2l6ZT42NTMxMjQgYnl0ZXM8L3NpemU+CiAgPC9zaXplcz4KICA8dmVyc2lvbj4xPC92ZXJzaW9uPgogIDxyaWdodHNMaXN0PgogICAgPHJpZ2h0cyByaWdodHNVUkk9Imh0dHBzOi8vc3BkeC5vcmcvbGljZW5zZXMvQ0MwLTEuMC5odG1sIj5DcmVhdGl2ZSBDb21tb25zIFplcm8gdjEuMCBVbml2ZXJzYWw8L3JpZ2h0cz4KICA8L3JpZ2h0c0xpc3Q+CiAgPGRlc2NyaXB0aW9ucz4KICAgIDxkZXNjcmlwdGlvbiBkZXNjcmlwdGlvblR5cGU9IkFic3RyYWN0Ij4KICAgICAgSW5jcmVhc2VkIGNhdGNobWVudCBlcm9zaW9uIGFuZCBudXRyaWVudCBsb2FkaW5nIGFyZSBjb21tb25seSByZWNvZ25pemVkCiAgICAgIGltcGFjdHMgb2YgZGVmb3Jlc3RhdGlvbiBvbiBnbG9iYWwgd2V0bGFuZHMuIEluIGNvbnRyYXN0LCBhbiBpbmNyZWFzZSBpbgogICAgICB3YXRlciBhdmFpbGFiaWxpdHkgaW4gZGVmb3Jlc3RlZCBjYXRjaG1lbnRzIGlzIHdlbGwga25vd24gaW4gbW9kZXJuCiAgICAgIHN0dWRpZXMgYnV0IGlzIHJhcmVseSBjb25zaWRlcmVkIHdoZW4gZXZhbHVhdGluZyBwYXN0IGh1bWFuIGltcGFjdHMuIFdlCiAgICAgIHVzZWQgYSBCdWR5a28gd2F0ZXIgYmFsYW5jZSBhcHByb2FjaCwgYSBtZXRhLWFuYWx5c2lzIG9mIGdsb2JhbCB3ZXRsYW5kCiAgICAgIHJlc3BvbnNlIHRvIGRlZm9yZXN0YXRpb24sIGFuZCBwYWxlb2Vjb2xvZ2ljYWwgc3R1ZGllcyBmcm9tIEF1c3RyYWxhc2lhIHRvCiAgICAgIGV4cGxvcmUgdGhpcyBpc3N1ZS4gQWZ0ZXIgY29tcGxldGUgZGVmb3Jlc3RhdGlvbiwgd2UgZGVtb25zdHJhdGVkIHRoYXQKICAgICAgd2F0ZXIgYXZhaWxhYmxlIHRvIHdldGxhbmRzIGluY3JlYXNlcyBieSB1cCB0byAxNSUgb2YgYW5udWFsCiAgICAgIHByZWNpcGl0YXRpb24uIFRoaXMgY2FuIGNvbnZlcnQgZXBoZW1lcmFsIHN3YW1wcyB0byBwZXJtYW5lbnQgbGFrZXMgb3IKICAgICAgZXZlbiBjcmVhdGUgbmV3IHdldGxhbmRzLiBUaGlzIGVmZmVjdCBpcyBnbG9iYWxseSBzaWduaWZpY2FudCwgd2l0aCA5IHRvCiAgICAgIDEyJSBvZiB3ZXRsYW5kcyBhZmZlY3RlZCwgaW5jbHVkaW5nIDIwIHRvIDQwJSBvZiBSYW1zYXIgd2V0bGFuZHMsIGJ1dCBpcwogICAgICB3aWRlbHkgdW5yZWNvZ25pemVkIGJlY2F1c2UgaHVtYW4gaW1wYWN0IHN0dWRpZXMgcmFyZWx5IHRlc3QgZm9yIGl0LgogICAgPC9kZXNjcmlwdGlvbj4KICAgIDxkZXNjcmlwdGlvbiBkZXNjcmlwdGlvblR5cGU9Ik90aGVyIj4KICAgICAgRGF0YWJhc2UgUzFEYXRhYmFzZSBTMSBpcyBhbiBFeGNlbCBzcHJlYWRzaGVldCB0aGF0IGNvbnRhaW5zIGRhdGEgZnJvbSBhbGwKICAgICAgc3R1ZGllcyBvZiBkZWZvcmVzdGF0aW9uIGluIHdldGxhbmQgY2F0Y2htZW50cyBkdXJpbmcgdGhlIEhvbG9jZW5lLiBUaGVzZQogICAgICBhcmUgdGhlIHBhcGVycyB1c2VkIGluIHRoZSBtZXRhLWFuYWx5c2lzLiBBbGwgc2l0ZXMgZXhhbWluZWQgYnkgZWFjaCBwYXBlcgogICAgICBhcmUgbGlzdGVkLiBUaGlzIGluZm9ybWF0aW9uIHdhcyBleHRyYWN0ZWQgZnJvbSBwdWJsaXNoZWQsIHBlZXItcmV2aWV3ZWQKICAgICAgam91cm5hbCBhcnRpY2xlc0RhdGFiYXNlIFMyRGF0YWJhc2UgUzIgY29udGFpbnMgaW5mb3JtYXRpb24gb24gc3BlY2lmaWMKICAgICAgc2l0ZXMgd2hlcmUgaHlkcm9sb2dpY2FsIGNoYW5nZXMgaGF2ZSBvY2N1cnJlZCBhZnRlciBkZWZvcmVzdGF0aW9uLlRoaXMKICAgICAgaW5mb3JtYXRpb24gd2FzIGV4dHJhY3RlZCBmcm9tIHB1Ymxpc2hlZCwgcGVlci1yZXZpZXdlZCBqb3VybmFsIGFydGljbGVzCiAgICAgIGxpc3RlZCBpbiBEYXRhYmFzZSBTMURhdGFiYXNlIFMzVGhpcyBpbmZvcm1hdGlvbiB3YXMgZXh0cmFjdGVkIGZyb20KICAgICAgcHVibGlzaGVkLCBwZWVyLXJldmlld2VkIGpvdXJuYWwgYXJ0aWNsZXMuIERhdGFiYXNlIFMzIGNvbnRhaW5zCiAgICAgIGluZm9ybWF0aW9uIHJlbGF0aW5nIHRvIHRoZSBtZXRhLWFuYWx5c2lzLiBEYXRhYmFzZSBTMyBjb250YWlucwogICAgICBpbmZvcm1hdGlvbiBmcm9tIGVhY2ggc2l0ZSB3aGVyZSBkZWZvcmVzdGF0aW9uIGFuZCB3ZXRsYW5kIGNoYW5nZSBkYXRhIGlzCiAgICAgIGF2YWlsYWJsZS4gUG9zdC1kZWZvcmVzdGF0aW9uIHdldGxhbmQgY2hhbmdlcyBhcmUgaWRlbnRpZmllZCBpbmNsdWRpbmc7IGEKICAgICAgY2hhbmdlIGluIHNlZGltZW50YXRpb24gcmF0ZSwgZXV0cm9waGljYXRpb24gb3IgY2hhbmdlIGluIGh5ZHJvbG9neS4KICAgIDwvZGVzY3JpcHRpb24+CiAgPC9kZXNjcmlwdGlvbnM+CiAgPGdlb0xvY2F0aW9ucz4KICAgIDxnZW9Mb2NhdGlvbj4KICAgICAgPGdlb0xvY2F0aW9uUGxhY2U+R2xvYmFsIGNvdmVyYWdlPC9nZW9Mb2NhdGlvblBsYWNlPgogICAgPC9nZW9Mb2NhdGlvbj4KICA8L2dlb0xvY2F0aW9ucz4KPC9yZXNvdXJjZT4=","url":"https://datadryad.org/dataset/doi:10.5061/dryad.m62gj","contentUrl":null,"metadataVersion":19,"schemaVersion":"http://datacite.org/schema/kernel-4","source":"mds","isActive":true,"state":"findable","reason":null,"viewCount":506,"viewsOverTime":[{"yearMonth":"2014-11","total":36},{"yearMonth":"2015-02","total":5},{"yearMonth":"2015-03","total":1},{"yearMonth":"2015-04","total":4},{"yearMonth":"2015-05","total":3},{"yearMonth":"2015-08","total":3},{"yearMonth":"2015-09","total":14},{"yearMonth":"2015-11","total":24},{"yearMonth":"2016-01","total":26},{"yearMonth":"2016-03","total":2},{"yearMonth":"2016-04","total":3},{"yearMonth":"2016-07","total":1},{"yearMonth":"2016-08","total":1},{"yearMonth":"2017-01","total":10},{"yearMonth":"2017-02","total":4},{"yearMonth":"2017-03","total":9},{"yearMonth":"2017-04","total":2},{"yearMonth":"2017-05","total":6},{"yearMonth":"2017-06","total":3},{"yearMonth":"2017-08","total":1},{"yearMonth":"2017-09","total":2},{"yearMonth":"2018-01","total":3},{"yearMonth":"2018-02","total":1},{"yearMonth":"2018-04","total":1},{"yearMonth":"2018-10","total":6},{"yearMonth":"2018-11","total":6},{"yearMonth":"2018-12","total":1},{"yearMonth":"2019-01","total":2},{"yearMonth":"2019-02","total":6},{"yearMonth":"2019-04","total":2},{"yearMonth":"2019-07","total":1},{"yearMonth":"2019-08","total":2},{"yearMonth":"2019-09","total":1},{"yearMonth":"2019-10","total":3},{"yearMonth":"2019-12","total":2},{"yearMonth":"2020-02","total":2},{"yearMonth":"2020-04","total":1},{"yearMonth":"2020-05","total":1},{"yearMonth":"2020-07","total":2},{"yearMonth":"2020-08","total":1},{"yearMonth":"2020-09","total":2},{"yearMonth":"2020-10","total":2},{"yearMonth":"2020-12","total":7},{"yearMonth":"2021-01","total":3},{"yearMonth":"2021-02","total":2},{"yearMonth":"2021-03","total":4},{"yearMonth":"2021-04","total":1},{"yearMonth":"2021-05","total":13},{"yearMonth":"2021-06","total":14},{"yearMonth":"2021-07","total":4},{"yearMonth":"2021-08","total":1},{"yearMonth":"2021-09","total":3},{"yearMonth":"2021-10","total":2},{"yearMonth":"2021-11","total":8},{"yearMonth":"2021-12","total":7},{"yearMonth":"2022-02","total":4},{"yearMonth":"2022-03","total":5},{"yearMonth":"2022-04","total":21},{"yearMonth":"2022-05","total":5},{"yearMonth":"2022-06","total":1},{"yearMonth":"2022-07","total":1},{"yearMonth":"2022-09","total":1},{"yearMonth":"2022-10","total":1},{"yearMonth":"2022-11","total":3},{"yearMonth":"2022-12","total":6},{"yearMonth":"2023-01","total":10},{"yearMonth":"2023-02","total":2},{"yearMonth":"2023-03","total":4},{"yearMonth":"2023-04","total":3},{"yearMonth":"2023-05","total":4},{"yearMonth":"2023-06","total":1},{"yearMonth":"2023-07","total":1},{"yearMonth":"2023-08","total":71},{"yearMonth":"2023-09","total":58},{"yearMonth":"2023-10","total":4},{"yearMonth":"2023-11","total":5},{"yearMonth":"2023-12","total":1},{"yearMonth":"2024-03","total":1},{"yearMonth":"2024-04","total":2},{"yearMonth":"2024-09","total":2},{"yearMonth":"2024-10","total":2},{"yearMonth":"2024-11","total":2},{"yearMonth":"2025-01","total":1},{"yearMonth":"2025-02","total":2},{"yearMonth":"2025-08","total":4},{"yearMonth":"2025-09","total":1}],"downloadCount":120,"downloadsOverTime":[{"yearMonth":"2014-11","total":3},{"yearMonth":"2015-02","total":1},{"yearMonth":"2015-04","total":1},{"yearMonth":"2015-05","total":1},{"yearMonth":"2015-08","total":2},{"yearMonth":"2015-09","total":14},{"yearMonth":"2015-11","total":22},{"yearMonth":"2016-01","total":21},{"yearMonth":"2016-03","total":1},{"yearMonth":"2016-04","total":2},{"yearMonth":"2016-07","total":1},{"yearMonth":"2017-01","total":7},{"yearMonth":"2017-02","total":2},{"yearMonth":"2017-03","total":5},{"yearMonth":"2017-04","total":2},{"yearMonth":"2017-05","total":1},{"yearMonth":"2017-06","total":2},{"yearMonth":"2018-01","total":3},{"yearMonth":"2018-10","total":1},{"yearMonth":"2018-11","total":4},{"yearMonth":"2019-01","total":1},{"yearMonth":"2019-04","total":1},{"yearMonth":"2019-08","total":1},{"yearMonth":"2019-10","total":1},{"yearMonth":"2020-05","total":1},{"yearMonth":"2020-12","total":2},{"yearMonth":"2021-05","total":1},{"yearMonth":"2021-06","total":2},{"yearMonth":"2021-07","total":1},{"yearMonth":"2021-08","total":1},{"yearMonth":"2021-09","total":1},{"yearMonth":"2021-10","total":1},{"yearMonth":"2021-11","total":1},{"yearMonth":"2022-11","total":1},{"yearMonth":"2023-10","total":3},{"yearMonth":"2023-11","total":1},{"yearMonth":"2023-12","total":1},{"yearMonth":"2024-03","total":1},{"yearMonth":"2024-04","total":1},{"yearMonth":"2024-09","total":0},{"yearMonth":"2024-10","total":1},{"yearMonth":"2024-11","total":0},{"yearMonth":"2025-01","total":0},{"yearMonth":"2025-02","total":0},{"yearMonth":"2025-08","total":0},{"yearMonth":"2025-09","total":0}],"referenceCount":1,"citationCount":1,"citationsOverTime":[{"year":"2019","total":1}],"partCount":3,"partOfCount":0,"versionCount":0,"versionOfCount":0,"created":"2014-10-30T15:25:41.000Z","registered":"2014-10-30T15:25:42.000Z","published":"2015","updated":"2025-07-21T14:21:48.000Z"},"relationships":{"client":{"data":{"id":"dryad.dryad","type":"clients"}},"provider":{"data":{"id":"dryad","type":"providers"}},"media":{"data":{"id":"10.5061/dryad.m62gj","type":"media"}},"references":{"data":[{"id":"10.1126/science.1260510","type":"dois"}]},"citations":{"data":[{"id":"10.1126/science.1260510","type":"dois"}]},"parts":{"data":[{"id":"10.5061/dryad.m62gj/1","type":"dois"},{"id":"10.5061/dryad.m62gj/2","type":"dois"},{"id":"10.5061/dryad.m62gj/3","type":"dois"}]},"partOf":{"data":[]},"versions":{"data":[]},"versionOf":{"data":[]}}}}' + recorded_at: Thu, 30 Oct 2025 20:16:56 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/doi_datacite_response_3.yml b/test/vcr_cassettes/doi/doi_datacite_response_3.yml new file mode 100644 index 0000000000..cc7ee93ed6 --- /dev/null +++ b/test/vcr_cassettes/doi/doi_datacite_response_3.yml @@ -0,0 +1,127 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.48550/arxiv.2404.12345 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:56 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Fp0y6eufWkSIf%2FT7SuAP0xg%2FCKIdkq6zDxmvIZ9yH4Xx%2FtNdE%2FK15aiT%2F4ltxsP8KoO0fmAfKNvKf4wyUueC4Y%2FvFJRCgkjx2me4XXshBNaaxA%3D%3D"}]}' + Cf-Ray: + - 996d97e1eecc4d7c-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.48550/arxiv.2404.12345", + "RA": "DataCite" + } + ] + recorded_at: Thu, 30 Oct 2025 20:16:56 GMT +- request: + method: get + uri: https://api.datacite.org/dois/10.48550/arxiv.2404.12345 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - application/json + User-Agent: + - Ruby + Host: + - api.datacite.org + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 20:16:56 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Status: + - 200 OK + X-Anonymous-Consumer: + - 'true' + Cache-Control: + - max-age=0, private, must-revalidate + Vary: + - Accept,Accept-Encoding + Referrer-Policy: + - strict-origin-when-cross-origin + X-Permitted-Cross-Domain-Policies: + - none + X-Xss-Protection: + - '0' + X-Request-Id: + - 89bdfd5d-f679-4468-be9e-ef5fac677a81 + Etag: + - W/"b48f41b9cc3b763914ff289b2f90131d" + X-Frame-Options: + - SAMEORIGIN + X-Runtime: + - '0.025023' + X-Content-Type-Options: + - nosniff + X-Powered-By: + - Phusion Passenger(R) 6.1.0 + Server: + - nginx/1.24.0 + Phusion Passenger(R) 6.1.0 + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Methods: + - GET, POST, PUT, PATCH, DELETE, OPTIONS + Access-Control-Allow-Headers: + - Accept,Access-Control-Allow-Origin,Access-Control-Expose-Headers,Access-Control-Allow-Methods,Access-Control-Allow-Headers,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With + Access-Control-Expose-Headers: + - Authorization + body: + encoding: ASCII-8BIT + string: !binary |- + eyJkYXRhIjp7ImlkIjoiMTAuNDg1NTAvYXJ4aXYuMjQwNC4xMjM0NSIsInR5cGUiOiJkb2lzIiwiYXR0cmlidXRlcyI6eyJkb2kiOiIxMC40ODU1MC9hcnhpdi4yNDA0LjEyMzQ1IiwicHJlZml4IjoiMTAuNDg1NTAiLCJzdWZmaXgiOiJhcnhpdi4yNDA0LjEyMzQ1IiwiaWRlbnRpZmllcnMiOlt7ImlkZW50aWZpZXIiOiIyNDA0LjEyMzQ1IiwiaWRlbnRpZmllclR5cGUiOiJhclhpdiJ9XSwiYWx0ZXJuYXRlSWRlbnRpZmllcnMiOlt7ImFsdGVybmF0ZUlkZW50aWZpZXJUeXBlIjoiYXJYaXYiLCJhbHRlcm5hdGVJZGVudGlmaWVyIjoiMjQwNC4xMjM0NSJ9XSwiY3JlYXRvcnMiOlt7Im5hbWUiOiJMaSwgU2h1YWkiLCJuYW1lVHlwZSI6IlBlcnNvbmFsIiwiZ2l2ZW5OYW1lIjoiU2h1YWkiLCJmYW1pbHlOYW1lIjoiTGkiLCJhZmZpbGlhdGlvbiI6W10sIm5hbWVJZGVudGlmaWVycyI6W119LHsibmFtZSI6IkdvbmcsIE1pbmciLCJuYW1lVHlwZSI6IlBlcnNvbmFsIiwiZ2l2ZW5OYW1lIjoiTWluZyIsImZhbWlseU5hbWUiOiJHb25nIiwiYWZmaWxpYXRpb24iOltdLCJuYW1lSWRlbnRpZmllcnMiOltdfSx7Im5hbWUiOiJMaSwgWXUtSGFuZyIsIm5hbWVUeXBlIjoiUGVyc29uYWwiLCJnaXZlbk5hbWUiOiJZdS1IYW5nIiwiZmFtaWx5TmFtZSI6IkxpIiwiYWZmaWxpYXRpb24iOltdLCJuYW1lSWRlbnRpZmllcnMiOltdfSx7Im5hbWUiOiJKaWFuZywgSHVhIiwibmFtZVR5cGUiOiJQZXJzb25hbCIsImdpdmVuTmFtZSI6Ikh1YSIsImZhbWlseU5hbWUiOiJKaWFuZyIsImFmZmlsaWF0aW9uIjpbXSwibmFtZUlkZW50aWZpZXJzIjpbXX0seyJuYW1lIjoiWGllLCBYLiBDLiIsIm5hbWVUeXBlIjoiUGVyc29uYWwiLCJnaXZlbk5hbWUiOiJYLiBDLiIsImZhbWlseU5hbWUiOiJYaWUiLCJhZmZpbGlhdGlvbiI6W10sIm5hbWVJZGVudGlmaWVycyI6W119XSwidGl0bGVzIjpbeyJ0aXRsZSI6IkhpZ2ggc3BpbiBheGlvbiBpbnN1bGF0b3IifV0sInB1Ymxpc2hlciI6ImFyWGl2IiwiY29udGFpbmVyIjp7fSwicHVibGljYXRpb25ZZWFyIjoyMDI0LCJzdWJqZWN0cyI6W3sibGFuZyI6ImVuIiwic3ViamVjdCI6Ik1lc29zY2FsZSBhbmQgTmFub3NjYWxlIFBoeXNpY3MgKGNvbmQtbWF0Lm1lcy1oYWxsKSIsInN1YmplY3RTY2hlbWUiOiJhclhpdiJ9LHsibGFuZyI6ImVuIiwic3ViamVjdCI6Ik1hdGVyaWFscyBTY2llbmNlIChjb25kLW1hdC5tdHJsLXNjaSkiLCJzdWJqZWN0U2NoZW1lIjoiYXJYaXYifSx7InN1YmplY3QiOiJGT1M6IFBoeXNpY2FsIHNjaWVuY2VzIiwic3ViamVjdFNjaGVtZSI6IkZpZWxkcyBvZiBTY2llbmNlIGFuZCBUZWNobm9sb2d5IChGT1MpIn0seyJzdWJqZWN0IjoiRk9TOiBQaHlzaWNhbCBzY2llbmNlcyIsInNjaGVtZVVyaSI6Imh0dHA6Ly93d3cub2VjZC5vcmcvc2NpZW5jZS9pbm5vLzM4MjM1MTQ3LnBkZiIsInN1YmplY3RTY2hlbWUiOiJGaWVsZHMgb2YgU2NpZW5jZSBhbmQgVGVjaG5vbG9neSAoRk9TKSJ9XSwiY29udHJpYnV0b3JzIjpbXSwiZGF0ZXMiOlt7ImRhdGUiOiIyMDI0LTA0LTE4VDE3OjIwOjE2WiIsImRhdGVUeXBlIjoiU3VibWl0dGVkIiwiZGF0ZUluZm9ybWF0aW9uIjoidjEifSx7ImRhdGUiOiIyMDI0LTA1LTI3VDAwOjE4OjA0WiIsImRhdGVUeXBlIjoiVXBkYXRlZCIsImRhdGVJbmZvcm1hdGlvbiI6InYxIn0seyJkYXRlIjoiMjAyNC0wNCIsImRhdGVUeXBlIjoiQXZhaWxhYmxlIiwiZGF0ZUluZm9ybWF0aW9uIjoidjEifSx7ImRhdGUiOiIyMDI0IiwiZGF0ZVR5cGUiOiJJc3N1ZWQifV0sImxhbmd1YWdlIjpudWxsLCJ0eXBlcyI6eyJyaXMiOiJSUFJUIiwiYmlidGV4IjoiYXJ0aWNsZSIsImNpdGVwcm9jIjoiYXJ0aWNsZS1qb3VybmFsIiwic2NoZW1hT3JnIjoiU2Nob2xhcmx5QXJ0aWNsZSIsInJlc291cmNlVHlwZSI6IkFydGljbGUiLCJyZXNvdXJjZVR5cGVHZW5lcmFsIjoiVGV4dCJ9LCJyZWxhdGVkSWRlbnRpZmllcnMiOlt7InJlbGF0aW9uVHlwZSI6IklzVmVyc2lvbk9mIiwicmVsYXRlZElkZW50aWZpZXIiOiIxMC4xMDM4L3M0MTQ2Ny0wMjQtNDg1NDItNCIsInJlbGF0ZWRJZGVudGlmaWVyVHlwZSI6IkRPSSJ9XSwicmVsYXRlZEl0ZW1zIjpbXSwic2l6ZXMiOltdLCJmb3JtYXRzIjpbXSwidmVyc2lvbiI6IjEiLCJyaWdodHNMaXN0IjpbeyJyaWdodHMiOiJhclhpdi5vcmcgcGVycGV0dWFsLCBub24tZXhjbHVzaXZlIGxpY2Vuc2UiLCJyaWdodHNVcmkiOiJodHRwOi8vYXJ4aXYub3JnL2xpY2Vuc2VzL25vbmV4Y2x1c2l2ZS1kaXN0cmliLzEuMC8ifV0sImRlc2NyaXB0aW9ucyI6W3siZGVzY3JpcHRpb24iOiJBeGlvbiBpbnN1bGF0b3JzIHBvc3Nlc3MgYSBxdWFudGl6ZWQgYXhpb24gZmllbGQgJM64Pc+AJCBwcm90ZWN0ZWQgYnkgY29tYmluZWQgbGF0dGljZSBhbmQgdGltZS1yZXZlcnNhbCBzeW1tZXRyeSwgaG9sZGluZyBncmVhdCBwb3RlbnRpYWwgZm9yIGRldmljZSBhcHBsaWNhdGlvbnMgaW4gbGF5ZXJ0cm9uaWNzIGFuZCBxdWFudHVtIGNvbXB1dGluZy4gSGVyZSwgd2UgcHJvcG9zZSBhIGhpZ2gtc3BpbiBheGlvbiBpbnN1bGF0b3IgKEhTQUkpIGRlZmluZWQgaW4gbGFyZ2Ugc3Bpbi0kcyQgcmVwcmVzZW50YXRpb24sIHdoaWNoIG1haW50YWlucyB0aGUgc2FtZSBpbmhlcmVudCBzeW1tZXRyeSBidXQgcG9zc2Vzc2VzIGEgbm90YWJsZSBheGlvbiBmaWVsZCAkzrg9KHMrMS8yKV4yz4AkLiBTdWNoIGRpc3RpbmN0IGF4aW9uIGZpZWxkIGlzIGNvbmZpcm1lZCBpbmRlcGVuZGVudGx5IGJ5IHRoZSBkaXJlY3QgY2FsY3VsYXRpb24gb2YgdGhlIGF4aW9uIHRlcm0gdXNpbmcgaHlicmlkIFdhbm5pZXIgZnVuY3Rpb25zLCBsYXllci1yZXNvbHZlZCBDaGVybiBudW1iZXJzLCBhcyB3ZWxsIGFzIHRoZSB0b3BvbG9naWNhbCBtYWduZXRvLWVsZWN0cmljIGVmZmVjdC4gV2Ugc2hvdyB0aGF0IHRoZSBndWFyYW50ZWVkIGdhcGxlc3MgcXVhc2ktcGFydGljbGUgZXhjaXRhdGlvbiBpcyBhYnNlbnQgYXQgdGhlIGJvdW5kYXJ5IG9mIHRoZSBIU0FJIGRlc3BpdGUgaXRzIGludGVnZXIgc3VyZmFjZSBDaGVybiBudW1iZXIsIGhpbnRpbmcgYW4gdW51c3VhbCBxdWFudHVtIGFub21hbHkgdmlvbGF0aW5nIHRoZSBjb252ZW50aW9uYWwgYnVsay1ib3VuZGFyeSBjb3JyZXNwb25kZW5jZS4gRnVydGhlcm1vcmUsIHdlIGFzY2VydGFpbiB0aGF0IHRoZSBheGlvbiBmaWVsZCAkzrgkIGNhbiBiZSBwcmVjaXNlbHkgdHVuZWQgdGhyb3VnaCBhbiBleHRlcm5hbCBtYWduZXRpYyBmaWVsZCwgZW5hYmxpbmcgdGhlIG1hbmlwdWxhdGlvbiBvZiBib25kZWQgdHJhbnNwb3J0IHByb3BlcnRpZXMuIFRoZSBIU0FJIHByb3Bvc2VkIGhlcmUgY2FuIGJlIGV4cGVyaW1lbnRhbGx5IHZlcmlmaWVkIGluIHVsdHJhLWNvbGQgYXRvbXMgYnkgdGhlIHF1YW50aXplZCBub24tcmVjaXByb2NhbCBjb25kdWN0YW5jZSBvciB0b3BvbG9naWNhbCBtYWduZXRvZWxlY3RyaWMgcmVzcG9uc2UuIE91ciB3b3JrIGVucmljaGVzIHRoZSB1bmRlcnN0YW5kaW5nIG9mIGF4aW9uIGluc3VsYXRvcnMgaW4gY29uZGVuc2VkIG1hdHRlciBwaHlzaWNzLCBwYXZpbmcgdGhlIHdheSBmb3IgZnV0dXJlIGRldmljZSBhcHBsaWNhdGlvbnMuIiwiZGVzY3JpcHRpb25UeXBlIjoiQWJzdHJhY3QifSx7ImRlc2NyaXB0aW9uIjoiVG8gYXBwZWFyIGluIE5hdHVyZSBDb21tdW5pY2F0aW9ucyIsImRlc2NyaXB0aW9uVHlwZSI6Ik90aGVyIn1dLCJnZW9Mb2NhdGlvbnMiOltdLCJmdW5kaW5nUmVmZXJlbmNlcyI6W10sInhtbCI6IlBEOTRiV3dnZG1WeWMybHZiajBpTVM0d0lpQmxibU52WkdsdVp6MGlWVlJHTFRnaVB6NEtQSEpsYzI5MWNtTmxJSGh0Ykc1elBTSm9kSFJ3T2k4dlpHRjBZV05wZEdVdWIzSm5MM05qYUdWdFlTOXJaWEp1Wld3dE5DSWdlRzFzYm5NNmVITnBQU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh5TURBeEwxaE5URk5qYUdWdFlTMXBibk4wWVc1alpTSWdlSE5wT25OamFHVnRZVXh2WTJGMGFXOXVQU0pvZEhSd09pOHZaR0YwWVdOcGRHVXViM0puTDNOamFHVnRZUzlyWlhKdVpXd3ROQ0JvZEhSd09pOHZjMk5vWlcxaExtUmhkR0ZqYVhSbExtOXlaeTl0WlhSaEwydGxjbTVsYkMwMExqTXZiV1YwWVdSaGRHRXVlSE5rSWo0S0lDQThhV1JsYm5ScFptbGxjaUJwWkdWdWRHbG1hV1Z5Vkhsd1pUMGlSRTlKSWo0eE1DNDBPRFUxTUM5QlVsaEpWaTR5TkRBMExqRXlNelExUEM5cFpHVnVkR2xtYVdWeVBnb2dJRHhoYkhSbGNtNWhkR1ZKWkdWdWRHbG1hV1Z5Y3o0S0lDQWdJRHhoYkhSbGNtNWhkR1ZKWkdWdWRHbG1hV1Z5SUdGc2RHVnlibUYwWlVsa1pXNTBhV1pwWlhKVWVYQmxQU0poY2xocGRpSStNalF3TkM0eE1qTTBOVHd2WVd4MFpYSnVZWFJsU1dSbGJuUnBabWxsY2o0S0lDQThMMkZzZEdWeWJtRjBaVWxrWlc1MGFXWnBaWEp6UGdvZ0lEeGpjbVZoZEc5eWN6NEtJQ0FnSUR4amNtVmhkRzl5UGdvZ0lDQWdJQ0E4WTNKbFlYUnZjazVoYldVZ2JtRnRaVlI1Y0dVOUlsQmxjbk52Ym1Gc0lqNU1hU3dnVTJoMVlXazhMMk55WldGMGIzSk9ZVzFsUGdvZ0lDQWdJQ0E4WjJsMlpXNU9ZVzFsUGxOb2RXRnBQQzluYVhabGJrNWhiV1UrQ2lBZ0lDQWdJRHhtWVcxcGJIbE9ZVzFsUGt4cFBDOW1ZVzFwYkhsT1lXMWxQZ29nSUNBZ1BDOWpjbVZoZEc5eVBnb2dJQ0FnUEdOeVpXRjBiM0krQ2lBZ0lDQWdJRHhqY21WaGRHOXlUbUZ0WlNCdVlXMWxWSGx3WlQwaVVHVnljMjl1WVd3aVBrZHZibWNzSUUxcGJtYzhMMk55WldGMGIzSk9ZVzFsUGdvZ0lDQWdJQ0E4WjJsMlpXNU9ZVzFsUGsxcGJtYzhMMmRwZG1WdVRtRnRaVDRLSUNBZ0lDQWdQR1poYldsc2VVNWhiV1UrUjI5dVp6d3ZabUZ0YVd4NVRtRnRaVDRLSUNBZ0lEd3ZZM0psWVhSdmNqNEtJQ0FnSUR4amNtVmhkRzl5UGdvZ0lDQWdJQ0E4WTNKbFlYUnZjazVoYldVZ2JtRnRaVlI1Y0dVOUlsQmxjbk52Ym1Gc0lqNU1hU3dnV1hVdFNHRnVaend2WTNKbFlYUnZjazVoYldVK0NpQWdJQ0FnSUR4bmFYWmxiazVoYldVK1dYVXRTR0Z1Wnp3dloybDJaVzVPWVcxbFBnb2dJQ0FnSUNBOFptRnRhV3g1VG1GdFpUNU1hVHd2Wm1GdGFXeDVUbUZ0WlQ0S0lDQWdJRHd2WTNKbFlYUnZjajRLSUNBZ0lEeGpjbVZoZEc5eVBnb2dJQ0FnSUNBOFkzSmxZWFJ2Y2s1aGJXVWdibUZ0WlZSNWNHVTlJbEJsY25OdmJtRnNJajVLYVdGdVp5d2dTSFZoUEM5amNtVmhkRzl5VG1GdFpUNEtJQ0FnSUNBZ1BHZHBkbVZ1VG1GdFpUNUlkV0U4TDJkcGRtVnVUbUZ0WlQ0S0lDQWdJQ0FnUEdaaGJXbHNlVTVoYldVK1NtbGhibWM4TDJaaGJXbHNlVTVoYldVK0NpQWdJQ0E4TDJOeVpXRjBiM0krQ2lBZ0lDQThZM0psWVhSdmNqNEtJQ0FnSUNBZ1BHTnlaV0YwYjNKT1lXMWxJRzVoYldWVWVYQmxQU0pRWlhKemIyNWhiQ0krV0dsbExDQllMaUJETGp3dlkzSmxZWFJ2Y2s1aGJXVStDaUFnSUNBZ0lEeG5hWFpsYms1aGJXVStXQzRnUXk0OEwyZHBkbVZ1VG1GdFpUNEtJQ0FnSUNBZ1BHWmhiV2xzZVU1aGJXVStXR2xsUEM5bVlXMXBiSGxPWVcxbFBnb2dJQ0FnUEM5amNtVmhkRzl5UGdvZ0lEd3ZZM0psWVhSdmNuTStDaUFnUEhScGRHeGxjejRLSUNBZ0lEeDBhWFJzWlQ1SWFXZG9JSE53YVc0Z1lYaHBiMjRnYVc1emRXeGhkRzl5UEM5MGFYUnNaVDRLSUNBOEwzUnBkR3hsY3o0S0lDQThjSFZpYkdsemFHVnlQbUZ5V0dsMlBDOXdkV0pzYVhOb1pYSStDaUFnUEhCMVlteHBZMkYwYVc5dVdXVmhjajR5TURJMFBDOXdkV0pzYVdOaGRHbHZibGxsWVhJK0NpQWdQSE4xWW1wbFkzUnpQZ29nSUNBZ1BITjFZbXBsWTNRZ2VHMXNPbXhoYm1jOUltVnVJaUJ6ZFdKcVpXTjBVMk5vWlcxbFBTSmhjbGhwZGlJK1RXVnpiM05qWVd4bElHRnVaQ0JPWVc1dmMyTmhiR1VnVUdoNWMybGpjeUFvWTI5dVpDMXRZWFF1YldWekxXaGhiR3dwUEM5emRXSnFaV04wUGdvZ0lDQWdQSE4xWW1wbFkzUWdlRzFzT214aGJtYzlJbVZ1SWlCemRXSnFaV04wVTJOb1pXMWxQU0poY2xocGRpSStUV0YwWlhKcFlXeHpJRk5qYVdWdVkyVWdLR052Ym1RdGJXRjBMbTEwY213dGMyTnBLVHd2YzNWaWFtVmpkRDRLSUNBZ0lEeHpkV0pxWldOMElITjFZbXBsWTNSVFkyaGxiV1U5SWtacFpXeGtjeUJ2WmlCVFkybGxibU5sSUdGdVpDQlVaV05vYm05c2IyZDVJQ2hHVDFNcElqNUdUMU02SUZCb2VYTnBZMkZzSUhOamFXVnVZMlZ6UEM5emRXSnFaV04wUGdvZ0lEd3ZjM1ZpYW1WamRITStDaUFnUEdSaGRHVnpQZ29nSUNBZ1BHUmhkR1VnWkdGMFpWUjVjR1U5SWxOMVltMXBkSFJsWkNJZ1pHRjBaVWx1Wm05eWJXRjBhVzl1UFNKMk1TSStNakF5TkMwd05DMHhPRlF4TnpveU1Eb3hObG84TDJSaGRHVStDaUFnSUNBOFpHRjBaU0JrWVhSbFZIbHdaVDBpVlhCa1lYUmxaQ0lnWkdGMFpVbHVabTl5YldGMGFXOXVQU0oyTVNJK01qQXlOQzB3TlMweU4xUXdNRG94T0Rvd05GbzhMMlJoZEdVK0NpQWdJQ0E4WkdGMFpTQmtZWFJsVkhsd1pUMGlRWFpoYVd4aFlteGxJaUJrWVhSbFNXNW1iM0p0WVhScGIyNDlJbll4SWo0eU1ESTBMVEEwUEM5a1lYUmxQZ29nSUR3dlpHRjBaWE0rQ2lBZ1BISmxjMjkxY21ObFZIbHdaU0J5WlhOdmRYSmpaVlI1Y0dWSFpXNWxjbUZzUFNKVVpYaDBJajVCY25ScFkyeGxQQzl5WlhOdmRYSmpaVlI1Y0dVK0NpQWdQSEpsYkdGMFpXUkpaR1Z1ZEdsbWFXVnljejRLSUNBZ0lEeHlaV3hoZEdWa1NXUmxiblJwWm1sbGNpQnlaV3hoZEdWa1NXUmxiblJwWm1sbGNsUjVjR1U5SWtSUFNTSWdjbVZzWVhScGIyNVVlWEJsUFNKSmMxWmxjbk5wYjI1UFppSStNVEF1TVRBek9DOXpOREUwTmpjdE1ESTBMVFE0TlRReUxUUThMM0psYkdGMFpXUkpaR1Z1ZEdsbWFXVnlQZ29nSUR3dmNtVnNZWFJsWkVsa1pXNTBhV1pwWlhKelBnb2dJRHgyWlhKemFXOXVQakU4TDNabGNuTnBiMjQrQ2lBZ1BISnBaMmgwYzB4cGMzUStDaUFnSUNBOGNtbG5hSFJ6SUhKcFoyaDBjMVZTU1QwaWFIUjBjRG92TDJGeWVHbDJMbTl5Wnk5c2FXTmxibk5sY3k5dWIyNWxlR05zZFhOcGRtVXRaR2x6ZEhKcFlpOHhMakF2SWo1aGNsaHBkaTV2Y21jZ2NHVnljR1YwZFdGc0xDQnViMjR0WlhoamJIVnphWFpsSUd4cFkyVnVjMlU4TDNKcFoyaDBjejRLSUNBOEwzSnBaMmgwYzB4cGMzUStDaUFnUEdSbGMyTnlhWEIwYVc5dWN6NEtJQ0FnSUR4a1pYTmpjbWx3ZEdsdmJpQmtaWE5qY21sd2RHbHZibFI1Y0dVOUlrRmljM1J5WVdOMElqNUJlR2x2YmlCcGJuTjFiR0YwYjNKeklIQnZjM05sYzNNZ1lTQnhkV0Z1ZEdsNlpXUWdZWGhwYjI0Z1ptbGxiR1FnSk02NFBjK0FKQ0J3Y205MFpXTjBaV1FnWW5rZ1kyOXRZbWx1WldRZ2JHRjBkR2xqWlNCaGJtUWdkR2x0WlMxeVpYWmxjbk5oYkNCemVXMXRaWFJ5ZVN3Z2FHOXNaR2x1WnlCbmNtVmhkQ0J3YjNSbGJuUnBZV3dnWm05eUlHUmxkbWxqWlNCaGNIQnNhV05oZEdsdmJuTWdhVzRnYkdGNVpYSjBjbTl1YVdOeklHRnVaQ0J4ZFdGdWRIVnRJR052YlhCMWRHbHVaeTRnU0dWeVpTd2dkMlVnY0hKdmNHOXpaU0JoSUdocFoyZ3RjM0JwYmlCaGVHbHZiaUJwYm5OMWJHRjBiM0lnS0VoVFFVa3BJR1JsWm1sdVpXUWdhVzRnYkdGeVoyVWdjM0JwYmkwa2N5UWdjbVZ3Y21WelpXNTBZWFJwYjI0c0lIZG9hV05vSUcxaGFXNTBZV2x1Y3lCMGFHVWdjMkZ0WlNCcGJtaGxjbVZ1ZENCemVXMXRaWFJ5ZVNCaWRYUWdjRzl6YzJWemMyVnpJR0VnYm05MFlXSnNaU0JoZUdsdmJpQm1hV1ZzWkNBa3pyZzlLSE1yTVM4eUtWNHl6NEFrTGlCVGRXTm9JR1JwYzNScGJtTjBJR0Y0YVc5dUlHWnBaV3hrSUdseklHTnZibVpwY20xbFpDQnBibVJsY0dWdVpHVnVkR3g1SUdKNUlIUm9aU0JrYVhKbFkzUWdZMkZzWTNWc1lYUnBiMjRnYjJZZ2RHaGxJR0Y0YVc5dUlIUmxjbTBnZFhOcGJtY2dhSGxpY21sa0lGZGhibTVwWlhJZ1puVnVZM1JwYjI1ekxDQnNZWGxsY2kxeVpYTnZiSFpsWkNCRGFHVnliaUJ1ZFcxaVpYSnpMQ0JoY3lCM1pXeHNJR0Z6SUhSb1pTQjBiM0J2Ykc5bmFXTmhiQ0J0WVdkdVpYUnZMV1ZzWldOMGNtbGpJR1ZtWm1WamRDNGdWMlVnYzJodmR5QjBhR0YwSUhSb1pTQm5kV0Z5WVc1MFpXVmtJR2RoY0d4bGMzTWdjWFZoYzJrdGNHRnlkR2xqYkdVZ1pYaGphWFJoZEdsdmJpQnBjeUJoWW5ObGJuUWdZWFFnZEdobElHSnZkVzVrWVhKNUlHOW1JSFJvWlNCSVUwRkpJR1JsYzNCcGRHVWdhWFJ6SUdsdWRHVm5aWElnYzNWeVptRmpaU0JEYUdWeWJpQnVkVzFpWlhJc0lHaHBiblJwYm1jZ1lXNGdkVzUxYzNWaGJDQnhkV0Z1ZEhWdElHRnViMjFoYkhrZ2RtbHZiR0YwYVc1bklIUm9aU0JqYjI1MlpXNTBhVzl1WVd3Z1luVnNheTFpYjNWdVpHRnllU0JqYjNKeVpYTndiMjVrWlc1alpTNGdSblZ5ZEdobGNtMXZjbVVzSUhkbElHRnpZMlZ5ZEdGcGJpQjBhR0YwSUhSb1pTQmhlR2x2YmlCbWFXVnNaQ0FrenJna0lHTmhiaUJpWlNCd2NtVmphWE5sYkhrZ2RIVnVaV1FnZEdoeWIzVm5hQ0JoYmlCbGVIUmxjbTVoYkNCdFlXZHVaWFJwWXlCbWFXVnNaQ3dnWlc1aFlteHBibWNnZEdobElHMWhibWx3ZFd4aGRHbHZiaUJ2WmlCaWIyNWtaV1FnZEhKaGJuTndiM0owSUhCeWIzQmxjblJwWlhNdUlGUm9aU0JJVTBGSklIQnliM0J2YzJWa0lHaGxjbVVnWTJGdUlHSmxJR1Y0Y0dWeWFXMWxiblJoYkd4NUlIWmxjbWxtYVdWa0lHbHVJSFZzZEhKaExXTnZiR1FnWVhSdmJYTWdZbmtnZEdobElIRjFZVzUwYVhwbFpDQnViMjR0Y21WamFYQnliMk5oYkNCamIyNWtkV04wWVc1alpTQnZjaUIwYjNCdmJHOW5hV05oYkNCdFlXZHVaWFJ2Wld4bFkzUnlhV01nY21WemNHOXVjMlV1SUU5MWNpQjNiM0pySUdWdWNtbGphR1Z6SUhSb1pTQjFibVJsY25OMFlXNWthVzVuSUc5bUlHRjRhVzl1SUdsdWMzVnNZWFJ2Y25NZ2FXNGdZMjl1WkdWdWMyVmtJRzFoZEhSbGNpQndhSGx6YVdOekxDQndZWFpwYm1jZ2RHaGxJSGRoZVNCbWIzSWdablYwZFhKbElHUmxkbWxqWlNCaGNIQnNhV05oZEdsdmJuTXVQQzlrWlhOamNtbHdkR2x2Ymo0S0lDQWdJRHhrWlhOamNtbHdkR2x2YmlCa1pYTmpjbWx3ZEdsdmJsUjVjR1U5SWs5MGFHVnlJajVVYnlCaGNIQmxZWElnYVc0Z1RtRjBkWEpsSUVOdmJXMTFibWxqWVhScGIyNXpQQzlrWlhOamNtbHdkR2x2Ymo0S0lDQThMMlJsYzJOeWFYQjBhVzl1Y3o0S1BDOXlaWE52ZFhKalpUND0iLCJ1cmwiOiJodHRwczovL2FyeGl2Lm9yZy9hYnMvMjQwNC4xMjM0NSIsImNvbnRlbnRVcmwiOm51bGwsIm1ldGFkYXRhVmVyc2lvbiI6MSwic2NoZW1hVmVyc2lvbiI6Imh0dHA6Ly9kYXRhY2l0ZS5vcmcvc2NoZW1hL2tlcm5lbC00Iiwic291cmNlIjoibWRzIiwiaXNBY3RpdmUiOnRydWUsInN0YXRlIjoiZmluZGFibGUiLCJyZWFzb24iOm51bGwsInZpZXdDb3VudCI6MCwidmlld3NPdmVyVGltZSI6W10sImRvd25sb2FkQ291bnQiOjAsImRvd25sb2Fkc092ZXJUaW1lIjpbXSwicmVmZXJlbmNlQ291bnQiOjAsImNpdGF0aW9uQ291bnQiOjAsImNpdGF0aW9uc092ZXJUaW1lIjpbXSwicGFydENvdW50IjowLCJwYXJ0T2ZDb3VudCI6MCwidmVyc2lvbkNvdW50IjowLCJ2ZXJzaW9uT2ZDb3VudCI6MSwiY3JlYXRlZCI6IjIwMjQtMDQtMTlUMDE6NDE6MjcuMDAwWiIsInJlZ2lzdGVyZWQiOiIyMDI0LTA0LTE5VDAxOjQxOjI4LjAwMFoiLCJwdWJsaXNoZWQiOiIyMDI0IiwidXBkYXRlZCI6IjIwMjQtMDUtMzFUMDI6MDg6NTEuMDAwWiJ9LCJyZWxhdGlvbnNoaXBzIjp7ImNsaWVudCI6eyJkYXRhIjp7ImlkIjoiYXJ4aXYuY29udGVudCIsInR5cGUiOiJjbGllbnRzIn19LCJwcm92aWRlciI6eyJkYXRhIjp7ImlkIjoiYXJ4aXYiLCJ0eXBlIjoicHJvdmlkZXJzIn19LCJtZWRpYSI6eyJkYXRhIjp7ImlkIjoiMTAuNDg1NTAvYXJ4aXYuMjQwNC4xMjM0NSIsInR5cGUiOiJtZWRpYSJ9fSwicmVmZXJlbmNlcyI6eyJkYXRhIjpbXX0sImNpdGF0aW9ucyI6eyJkYXRhIjpbXX0sInBhcnRzIjp7ImRhdGEiOltdfSwicGFydE9mIjp7ImRhdGEiOltdfSwidmVyc2lvbnMiOnsiZGF0YSI6W119LCJ2ZXJzaW9uT2YiOnsiZGF0YSI6W3siaWQiOiIxMC4xMDM4L3M0MTQ2Ny0wMjQtNDg1NDItNCIsInR5cGUiOiJkb2lzIn1dfX19fQ== + recorded_at: Thu, 30 Oct 2025 20:16:56 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/fake_doi.yml b/test/vcr_cassettes/doi/fake_doi.yml new file mode 100644 index 0000000000..be278680b6 --- /dev/null +++ b/test/vcr_cassettes/doi/fake_doi.yml @@ -0,0 +1,58 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.19232/fake.2020.1.23 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 12:29:59 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=IIZijPa58CPJNmBG8kYLWxZz9M7ZkezwIF9BiTYXfUE5qEhdi%2FwObH%2FLwHH82V48eg5cTO8ebcFqMY176kGHT5nGv36WPg%3D%3D"}]}' + Cf-Ray: + - 996aebdaed0dd3b9-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.19232/fake.2020.1.23", + "status": "DOI does not exist" + } + ] + recorded_at: Thu, 30 Oct 2025 12:29:58 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/invalid_doi.yml b/test/vcr_cassettes/doi/invalid_doi.yml new file mode 100644 index 0000000000..59481f9580 --- /dev/null +++ b/test/vcr_cassettes/doi/invalid_doi.yml @@ -0,0 +1,58 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/hello_march + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 15:31:01 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=%2FY%2F0LsBv4nb54CsXKaprfzHww6Uut2JxJZE3fQjTU6lskyXEta8WfOLlVjAqH3jb74BCge8Ro10HPqwuY6gt6kZaL%2BoZYw%3D%3D"}]}' + Cf-Ray: + - 996bf510fd316e96-STR + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "hello_march", + "status": "Invalid DOI" + } + ] + recorded_at: Thu, 30 Oct 2025 15:31:01 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/invalid_json_response.yml b/test/vcr_cassettes/doi/invalid_json_response.yml new file mode 100644 index 0000000000..3570445973 --- /dev/null +++ b/test/vcr_cassettes/doi/invalid_json_response.yml @@ -0,0 +1,46 @@ +--- +http_interactions: + - request: + method: get + uri: https://doi.org/ra/10.1016/j.patter.2025.101345 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + body: + encoding: UTF-8 + string: '[{"DOI": "10.1016/j.patter.2025.101345", "RA": "Crossref"}]' + http_version: + recorded_at: Wed, 29 Oct 2025 00:00:00 GMT + + - request: + method: get + uri: https://api.crossref.org/works/10.1016/j.patter.2025.101345 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + body: + encoding: UTF-8 + string: "This is not valid JSON!" + http_version: + recorded_at: Wed, 29 Oct 2025 00:00:00 GMT +recorded_with: VCR 6.2.0 diff --git a/test/vcr_cassettes/doi/malformed_doi.yml b/test/vcr_cassettes/doi/malformed_doi.yml new file mode 100644 index 0000000000..697d4c8ebb --- /dev/null +++ b/test/vcr_cassettes/doi/malformed_doi.yml @@ -0,0 +1,58 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.1.11.1 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Fri, 31 Oct 2025 08:26:29 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Jwt13zdTW%2BkznozukCv3g%2F7r%2FSV4DwFEQdx8oMXftsRDZ8a8ButjoYA1aVCpq5TNpBZJxsoHDK8Pqf4XK1Qm%2FOM2ZM0wKpmVIC8%2Ba%2BD8EcsO9w%3D%3D"}]}' + Cf-Ray: + - 9971c48f5c84d280-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.1.11.1", + "status": "DOI does not exist" + } + ] + recorded_at: Fri, 31 Oct 2025 08:26:29 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/doi/medra_ra.yml b/test/vcr_cassettes/doi/medra_ra.yml new file mode 100644 index 0000000000..91e968682e --- /dev/null +++ b/test/vcr_cassettes/doi/medra_ra.yml @@ -0,0 +1,58 @@ +--- +http_interactions: +- request: + method: get + uri: https://doi.org/ra/10.19232/uv4pb.2018.2.00 + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 30 Oct 2025 15:22:32 GMT + Content-Type: + - application/json;charset=UTF-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + Vary: + - Origin + - accept-encoding + Permissions-Policy: + - interest-cohort=(),browsing-topics=() + Cf-Cache-Status: + - DYNAMIC + Nel: + - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Report-To: + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=qbybHuHwC0H7O8VYvmAGDk5p5d7DJdw%2Bc3DiYfN3awLV41nr%2FYrcwR7TI6O13ObGGaVH96QOuzqHX3X%2B%2BBdJxLVBQgLUdA%3D%3D"}]}' + Cf-Ray: + - 996be89c9c436e96-STR + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: |- + [ + { + "DOI": "10.19232/uv4pb.2018.2.00", + "RA": "mEDRA" + } + ] + recorded_at: Thu, 30 Oct 2025 15:22:31 GMT +recorded_with: VCR 6.3.1 diff --git a/test/vcr_cassettes/publications/fairdom_by_doi.yml b/test/vcr_cassettes/publications/fairdom_by_doi.yml deleted file mode 100644 index 621a884030..0000000000 --- a/test/vcr_cassettes/publications/fairdom_by_doi.yml +++ /dev/null @@ -1,41 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://doi.crossref.org/openurl?format=unixref&id=doi:10.1093/nar/gkw1032&noredirect=true&pid=sowen@cs.man.ac.uk - body: - encoding: US-ASCII - string: '' - headers: - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - response: - status: - code: 200 - message: OK - headers: - Server: - - Apache-Coyote/1.1 - Crossref-Deployment-Name: - - cr6-1 - Content-Type: - - text/xml;charset=UTF-8 - Content-Language: - - en-US - Transfer-Encoding: - - chunked - Date: - - Mon, 14 Oct 2019 08:15:18 GMT - Connection: - - close - body: - encoding: ASCII-8BIT - string: !binary |- - PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPGRvaV9yZWNvcmRzPg0KICA8ZG9pX3JlY29yZCBvd25lcj0iMTAuMTA5MyIgdGltZXN0YW1wPSIyMDE5LTA5LTE1IDAxOjE4OjI4Ij4NCiAgICA8Y3Jvc3NyZWY+DQogICAgICA8am91cm5hbD4NCiAgICAgICAgPGpvdXJuYWxfbWV0YWRhdGEgbGFuZ3VhZ2U9ImVuIj4NCiAgICAgICAgICA8ZnVsbF90aXRsZT5OdWNsZWljIEFjaWRzIFJlc2VhcmNoPC9mdWxsX3RpdGxlPg0KICAgICAgICAgIDxhYmJyZXZfdGl0bGU+TnVjbGVpYyBBY2lkcyBSZXM8L2FiYnJldl90aXRsZT4NCiAgICAgICAgICA8aXNzbiBtZWRpYV90eXBlPSJwcmludCI+MDMwNS0xMDQ4PC9pc3NuPg0KICAgICAgICAgIDxpc3NuIG1lZGlhX3R5cGU9ImVsZWN0cm9uaWMiPjEzNjItNDk2MjwvaXNzbj4NCiAgICAgICAgPC9qb3VybmFsX21ldGFkYXRhPg0KICAgICAgICA8am91cm5hbF9pc3N1ZT4NCiAgICAgICAgICA8cHVibGljYXRpb25fZGF0ZSBtZWRpYV90eXBlPSJvbmxpbmUiPg0KICAgICAgICAgICAgPG1vbnRoPjAxPC9tb250aD4NCiAgICAgICAgICAgIDxkYXk+MDM8L2RheT4NCiAgICAgICAgICAgIDx5ZWFyPjIwMTc8L3llYXI+DQogICAgICAgICAgPC9wdWJsaWNhdGlvbl9kYXRlPg0KICAgICAgICAgIDxwdWJsaWNhdGlvbl9kYXRlIG1lZGlhX3R5cGU9InByaW50Ij4NCiAgICAgICAgICAgIDxtb250aD4wMTwvbW9udGg+DQogICAgICAgICAgICA8ZGF5PjA0PC9kYXk+DQogICAgICAgICAgICA8eWVhcj4yMDE3PC95ZWFyPg0KICAgICAgICAgIDwvcHVibGljYXRpb25fZGF0ZT4NCiAgICAgICAgICA8am91cm5hbF92b2x1bWU+DQogICAgICAgICAgICA8dm9sdW1lPjQ1PC92b2x1bWU+DQogICAgICAgICAgPC9qb3VybmFsX3ZvbHVtZT4NCiAgICAgICAgICA8aXNzdWU+RDE8L2lzc3VlPg0KICAgICAgICA8L2pvdXJuYWxfaXNzdWU+DQogICAgICAgIDxqb3VybmFsX2FydGljbGUgcHVibGljYXRpb25fdHlwZT0iZnVsbF90ZXh0Ij4NCiAgICAgICAgICA8dGl0bGVzPg0KICAgICAgICAgICAgPHRpdGxlPkZBSVJET01IdWI6IGEgcmVwb3NpdG9yeSBhbmQgY29sbGFib3JhdGlvbiBlbnZpcm9ubWVudCBmb3Igc2hhcmluZyBzeXN0ZW1zIGJpb2xvZ3kgcmVzZWFyY2g8L3RpdGxlPg0KICAgICAgICAgIDwvdGl0bGVzPg0KICAgICAgICAgIDxjb250cmlidXRvcnM+DQogICAgICAgICAgICA8cGVyc29uX25hbWUgY29udHJpYnV0b3Jfcm9sZT0iYXV0aG9yIiBzZXF1ZW5jZT0iZmlyc3QiPg0KICAgICAgICAgICAgICA8Z2l2ZW5fbmFtZT5LYXRoZXJpbmU8L2dpdmVuX25hbWU+DQogICAgICAgICAgICAgIDxzdXJuYW1lPldvbHN0ZW5jcm9mdDwvc3VybmFtZT4NCiAgICAgICAgICAgIDwvcGVyc29uX25hbWU+DQogICAgICAgICAgICA8cGVyc29uX25hbWUgY29udHJpYnV0b3Jfcm9sZT0iYXV0aG9yIiBzZXF1ZW5jZT0iYWRkaXRpb25hbCI+DQogICAgICAgICAgICAgIDxnaXZlbl9uYW1lPk9sZ2E8L2dpdmVuX25hbWU+DQogICAgICAgICAgICAgIDxzdXJuYW1lPktyZWJzPC9zdXJuYW1lPg0KICAgICAgICAgICAgPC9wZXJzb25fbmFtZT4NCiAgICAgICAgICAgIDxwZXJzb25fbmFtZSBjb250cmlidXRvcl9yb2xlPSJhdXRob3IiIHNlcXVlbmNlPSJhZGRpdGlvbmFsIj4NCiAgICAgICAgICAgICAgPGdpdmVuX25hbWU+SmFja3kgTC48L2dpdmVuX25hbWU+DQogICAgICAgICAgICAgIDxzdXJuYW1lPlNub2VwPC9zdXJuYW1lPg0KICAgICAgICAgICAgPC9wZXJzb25fbmFtZT4NCiAgICAgICAgICAgIDxwZXJzb25fbmFtZSBjb250cmlidXRvcl9yb2xlPSJhdXRob3IiIHNlcXVlbmNlPSJhZGRpdGlvbmFsIj4NCiAgICAgICAgICAgICAgPGdpdmVuX25hbWU+TmF0YWxpZSBKLjwvZ2l2ZW5fbmFtZT4NCiAgICAgICAgICAgICAgPHN1cm5hbWU+U3RhbmZvcmQ8L3N1cm5hbWU+DQogICAgICAgICAgICA8L3BlcnNvbl9uYW1lPg0KICAgICAgICAgICAgPHBlcnNvbl9uYW1lIGNvbnRyaWJ1dG9yX3JvbGU9ImF1dGhvciIgc2VxdWVuY2U9ImFkZGl0aW9uYWwiPg0KICAgICAgICAgICAgICA8Z2l2ZW5fbmFtZT5GaW5uPC9naXZlbl9uYW1lPg0KICAgICAgICAgICAgICA8c3VybmFtZT5CYWNhbGw8L3N1cm5hbWU+DQogICAgICAgICAgICA8L3BlcnNvbl9uYW1lPg0KICAgICAgICAgICAgPHBlcnNvbl9uYW1lIGNvbnRyaWJ1dG9yX3JvbGU9ImF1dGhvciIgc2VxdWVuY2U9ImFkZGl0aW9uYWwiPg0KICAgICAgICAgICAgICA8Z2l2ZW5fbmFtZT5NYXJ0aW48L2dpdmVuX25hbWU+DQogICAgICAgICAgICAgIDxzdXJuYW1lPkdvbGViaWV3c2tpPC9zdXJuYW1lPg0KICAgICAgICAgICAgPC9wZXJzb25fbmFtZT4NCiAgICAgICAgICAgIDxwZXJzb25fbmFtZSBjb250cmlidXRvcl9yb2xlPSJhdXRob3IiIHNlcXVlbmNlPSJhZGRpdGlvbmFsIj4NCiAgICAgICAgICAgICAgPGdpdmVuX25hbWU+Um9zdHlrPC9naXZlbl9uYW1lPg0KICAgICAgICAgICAgICA8c3VybmFtZT5LdXp5YWtpdjwvc3VybmFtZT4NCiAgICAgICAgICAgIDwvcGVyc29uX25hbWU+DQogICAgICAgICAgICA8cGVyc29uX25hbWUgY29udHJpYnV0b3Jfcm9sZT0iYXV0aG9yIiBzZXF1ZW5jZT0iYWRkaXRpb25hbCI+DQogICAgICAgICAgICAgIDxnaXZlbl9uYW1lPlF1eWVuPC9naXZlbl9uYW1lPg0KICAgICAgICAgICAgICA8c3VybmFtZT5OZ3V5ZW48L3N1cm5hbWU+DQogICAgICAgICAgICA8L3BlcnNvbl9uYW1lPg0KICAgICAgICAgICAgPHBlcnNvbl9uYW1lIGNvbnRyaWJ1dG9yX3JvbGU9ImF1dGhvciIgc2VxdWVuY2U9ImFkZGl0aW9uYWwiPg0KICAgICAgICAgICAgICA8Z2l2ZW5fbmFtZT5TdHVhcnQ8L2dpdmVuX25hbWU+DQogICAgICAgICAgICAgIDxzdXJuYW1lPk93ZW48L3N1cm5hbWU+DQogICAgICAgICAgICA8L3BlcnNvbl9uYW1lPg0KICAgICAgICAgICAgPHBlcnNvbl9uYW1lIGNvbnRyaWJ1dG9yX3JvbGU9ImF1dGhvciIgc2VxdWVuY2U9ImFkZGl0aW9uYWwiPg0KICAgICAgICAgICAgICA8Z2l2ZW5fbmFtZT5TdGlhbjwvZ2l2ZW5fbmFtZT4NCiAgICAgICAgICAgICAgPHN1cm5hbWU+U29pbGFuZC1SZXllczwvc3VybmFtZT4NCiAgICAgICAgICAgIDwvcGVyc29uX25hbWU+DQogICAgICAgICAgICA8cGVyc29uX25hbWUgY29udHJpYnV0b3Jfcm9sZT0iYXV0aG9yIiBzZXF1ZW5jZT0iYWRkaXRpb25hbCI+DQogICAgICAgICAgICAgIDxnaXZlbl9uYW1lPkpha3ViPC9naXZlbl9uYW1lPg0KICAgICAgICAgICAgICA8c3VybmFtZT5TdHJhc3pld3NraTwvc3VybmFtZT4NCiAgICAgICAgICAgIDwvcGVyc29uX25hbWU+DQogICAgICAgICAgICA8cGVyc29uX25hbWUgY29udHJpYnV0b3Jfcm9sZT0iYXV0aG9yIiBzZXF1ZW5jZT0iYWRkaXRpb25hbCI+DQogICAgICAgICAgICAgIDxnaXZlbl9uYW1lPkRhdmlkIEQuPC9naXZlbl9uYW1lPg0KICAgICAgICAgICAgICA8c3VybmFtZT52YW7CoE5pZWtlcms8L3N1cm5hbWU+DQogICAgICAgICAgICA8L3BlcnNvbl9uYW1lPg0KICAgICAgICAgICAgPHBlcnNvbl9uYW1lIGNvbnRyaWJ1dG9yX3JvbGU9ImF1dGhvciIgc2VxdWVuY2U9ImFkZGl0aW9uYWwiPg0KICAgICAgICAgICAgICA8Z2l2ZW5fbmFtZT5BbGFuIFIuPC9naXZlbl9uYW1lPg0KICAgICAgICAgICAgICA8c3VybmFtZT5XaWxsaWFtczwvc3VybmFtZT4NCiAgICAgICAgICAgIDwvcGVyc29uX25hbWU+DQogICAgICAgICAgICA8cGVyc29uX25hbWUgY29udHJpYnV0b3Jfcm9sZT0iYXV0aG9yIiBzZXF1ZW5jZT0iYWRkaXRpb25hbCI+DQogICAgICAgICAgICAgIDxnaXZlbl9uYW1lPkxhcnM8L2dpdmVuX25hbWU+DQogICAgICAgICAgICAgIDxzdXJuYW1lPk1hbG1zdHLDtm08L3N1cm5hbWU+DQogICAgICAgICAgICA8L3BlcnNvbl9uYW1lPg0KICAgICAgICAgICAgPHBlcnNvbl9uYW1lIGNvbnRyaWJ1dG9yX3JvbGU9ImF1dGhvciIgc2VxdWVuY2U9ImFkZGl0aW9uYWwiPg0KICAgICAgICAgICAgICA8Z2l2ZW5fbmFtZT5CZXJuZDwvZ2l2ZW5fbmFtZT4NCiAgICAgICAgICAgICAgPHN1cm5hbWU+Umlubjwvc3VybmFtZT4NCiAgICAgICAgICAgIDwvcGVyc29uX25hbWU+DQogICAgICAgICAgICA8cGVyc29uX25hbWUgY29udHJpYnV0b3Jfcm9sZT0iYXV0aG9yIiBzZXF1ZW5jZT0iYWRkaXRpb25hbCI+DQogICAgICAgICAgICAgIDxnaXZlbl9uYW1lPldvbGZnYW5nPC9naXZlbl9uYW1lPg0KICAgICAgICAgICAgICA8c3VybmFtZT5Nw7xsbGVyPC9zdXJuYW1lPg0KICAgICAgICAgICAgPC9wZXJzb25fbmFtZT4NCiAgICAgICAgICAgIDxwZXJzb25fbmFtZSBjb250cmlidXRvcl9yb2xlPSJhdXRob3IiIHNlcXVlbmNlPSJhZGRpdGlvbmFsIj4NCiAgICAgICAgICAgICAgPGdpdmVuX25hbWU+Q2Fyb2xlPC9naXZlbl9uYW1lPg0KICAgICAgICAgICAgICA8c3VybmFtZT5Hb2JsZTwvc3VybmFtZT4NCiAgICAgICAgICAgIDwvcGVyc29uX25hbWU+DQogICAgICAgICAgPC9jb250cmlidXRvcnM+DQogICAgICAgICAgPHB1YmxpY2F0aW9uX2RhdGUgbWVkaWFfdHlwZT0icHJpbnQiPg0KICAgICAgICAgICAgPG1vbnRoPjAxPC9tb250aD4NCiAgICAgICAgICAgIDxkYXk+MDQ8L2RheT4NCiAgICAgICAgICAgIDx5ZWFyPjIwMTc8L3llYXI+DQogICAgICAgICAgPC9wdWJsaWNhdGlvbl9kYXRlPg0KICAgICAgICAgIDxwdWJsaWNhdGlvbl9kYXRlIG1lZGlhX3R5cGU9Im9ubGluZSI+DQogICAgICAgICAgICA8bW9udGg+MTE8L21vbnRoPg0KICAgICAgICAgICAgPGRheT4yODwvZGF5Pg0KICAgICAgICAgICAgPHllYXI+MjAxNjwveWVhcj4NCiAgICAgICAgICA8L3B1YmxpY2F0aW9uX2RhdGU+DQogICAgICAgICAgPHBhZ2VzPg0KICAgICAgICAgICAgPGZpcnN0X3BhZ2U+RDQwNDwvZmlyc3RfcGFnZT4NCiAgICAgICAgICAgIDxsYXN0X3BhZ2U+RDQwNzwvbGFzdF9wYWdlPg0KICAgICAgICAgIDwvcGFnZXM+DQogICAgICAgICAgPHB1Ymxpc2hlcl9pdGVtPg0KICAgICAgICAgICAgPGl0ZW1fbnVtYmVyIGl0ZW1fbnVtYmVyX3R5cGU9ImF0b20iPi9uYXIvNDUvRDEvRDQwNC5hdG9tPC9pdGVtX251bWJlcj4NCiAgICAgICAgICAgIDxpZGVudGlmaWVyIGlkX3R5cGU9ImRvaSI+MTAuMTA5My9uYXIvZ2t3MTAzMjwvaWRlbnRpZmllcj4NCiAgICAgICAgICA8L3B1Ymxpc2hlcl9pdGVtPg0KICAgICAgICAgIDxwcm9ncmFtIG5hbWU9IkFjY2Vzc0luZGljYXRvcnMiPg0KICAgICAgICAgICAgPGxpY2Vuc2VfcmVmIGFwcGxpZXNfdG89InZvciIgc3RhcnRfZGF0ZT0iMjAxNi0xMS0yNCI+aHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnkvNC4wLzwvbGljZW5zZV9yZWY+DQogICAgICAgICAgPC9wcm9ncmFtPg0KICAgICAgICAgIDxkb2lfZGF0YT4NCiAgICAgICAgICAgIDxkb2k+MTAuMTA5My9uYXIvZ2t3MTAzMjwvZG9pPg0KICAgICAgICAgICAgPHRpbWVzdGFtcD4yMDE3MDEwMzIzMTUxMjYyMDAwPC90aW1lc3RhbXA+DQogICAgICAgICAgICA8cmVzb3VyY2U+aHR0cHM6Ly9hY2FkZW1pYy5vdXAuY29tL25hci9hcnRpY2xlLWxvb2t1cC9kb2kvMTAuMTA5My9uYXIvZ2t3MTAzMjwvcmVzb3VyY2U+DQogICAgICAgICAgICA8Y29sbGVjdGlvbiBwcm9wZXJ0eT0iY3Jhd2xlci1iYXNlZCI+DQogICAgICAgICAgICAgIDxpdGVtIGNyYXdsZXI9ImlQYXJhZGlnbXMiPg0KICAgICAgICAgICAgICAgIDxyZXNvdXJjZT5odHRwOi8vYWNhZGVtaWMub3VwLmNvbS9uYXIvYXJ0aWNsZS1wZGYvNDUvRDEvRDQwNC84ODQ2NjMxL2drdzEwMzIucGRmPC9yZXNvdXJjZT4NCiAgICAgICAgICAgICAgPC9pdGVtPg0KICAgICAgICAgICAgPC9jb2xsZWN0aW9uPg0KICAgICAgICAgIDwvZG9pX2RhdGE+DQogICAgICAgICAgPGNpdGF0aW9uX2xpc3Q+DQogICAgICAgICAgICA8Y2l0YXRpb24ga2V5PSIyMDE3MDEwMzIzMTUxMjYyMDAwXzQ1LkQxLkQ0MDQuMSI+DQogICAgICAgICAgICAgIDxkb2k+MTAuMTE4Ni8xNDcxLTIxMDUtMTItNDY4PC9kb2k+DQogICAgICAgICAgICA8L2NpdGF0aW9uPg0KICAgICAgICAgICAgPGNpdGF0aW9uIGtleT0iMjAxNzAxMDMyMzE1MTI2MjAwMF80NS5EMS5ENDA0LjIiPg0KICAgICAgICAgICAgICA8am91cm5hbF90aXRsZT5CTUMgU3lzdC4gQmlvbC48L2pvdXJuYWxfdGl0bGU+DQogICAgICAgICAgICAgIDxhdXRob3I+V29sc3RlbmNyb2Z0PC9hdXRob3I+DQogICAgICAgICAgICAgIDx2b2x1bWU+OTwvdm9sdW1lPg0KICAgICAgICAgICAgICA8Zmlyc3RfcGFnZT4zPC9maXJzdF9wYWdlPg0KICAgICAgICAgICAgICA8Y1llYXI+MjAxNTwvY1llYXI+DQogICAgICAgICAgICAgIDxkb2kgcHJvdmlkZXI9ImNyb3NzcmVmIj4xMC4xMTg2L3MxMjkxOC0wMTUtMDE3NC15PC9kb2k+DQogICAgICAgICAgICAgIDxhcnRpY2xlX3RpdGxlPlNFRUs6IGEgc3lzdGVtcyBiaW9sb2d5IGRhdGEgYW5kIG1vZGVsIG1hbmFnZW1lbnQgcGxhdGZvcm08L2FydGljbGVfdGl0bGU+DQogICAgICAgICAgICA8L2NpdGF0aW9uPg0KICAgICAgICAgICAgPGNpdGF0aW9uIGtleT0iMjAxNzAxMDMyMzE1MTI2MjAwMF80NS5EMS5ENDA0LjMiPg0KICAgICAgICAgICAgICA8ZG9pPjEwLjExMTEvZmVicy4xMzIzNzwvZG9pPg0KICAgICAgICAgICAgPC9jaXRhdGlvbj4NCiAgICAgICAgICAgIDxjaXRhdGlvbiBrZXk9IjIwMTcwMTAzMjMxNTEyNjIwMDBfNDUuRDEuRDQwNC40Ij4NCiAgICAgICAgICAgICAgPGRvaT4xMC4xMDkzL25hci9na3IxMDQ2PC9kb2k+DQogICAgICAgICAgICA8L2NpdGF0aW9uPg0KICAgICAgICAgICAgPGNpdGF0aW9uIGtleT0iMjAxNzAxMDMyMzE1MTI2MjAwMF80NS5EMS5ENDA0LjUiPg0KICAgICAgICAgICAgICA8ZG9pPjEwLjExODYvMTc1Mi0wNTA5LTQtOTI8L2RvaT4NCiAgICAgICAgICAgIDwvY2l0YXRpb24+DQogICAgICAgICAgICA8Y2l0YXRpb24ga2V5PSIyMDE3MDEwMzIzMTUxMjYyMDAwXzQ1LkQxLkQ0MDQuNiI+DQogICAgICAgICAgICAgIDxkb2k+MTAuMTA5My9iaW9pbmZvcm1hdGljcy9idHIzMTI8L2RvaT4NCiAgICAgICAgICAgIDwvY2l0YXRpb24+DQogICAgICAgICAgICA8Y2l0YXRpb24ga2V5PSIyMDE3MDEwMzIzMTUxMjYyMDAwXzQ1LkQxLkQ0MDQuNyI+DQogICAgICAgICAgICAgIDxkb2k+MTAuMTAzOC9uYnQxMTU2PC9kb2k+DQogICAgICAgICAgICA8L2NpdGF0aW9uPg0KICAgICAgICAgICAgPGNpdGF0aW9uIGtleT0iMjAxNzAxMDMyMzE1MTI2MjAwMF80NS5EMS5ENDA0LjgiPg0KICAgICAgICAgICAgICA8ZG9pPjEwLjEwOTMvYmlvaW5mb3JtYXRpY3MvYnRoMjAwPC9kb2k+DQogICAgICAgICAgICA8L2NpdGF0aW9uPg0KICAgICAgICAgICAgPGNpdGF0aW9uIGtleT0iMjAxNzAxMDMyMzE1MTI2MjAwMF80NS5EMS5ENDA0LjkiPg0KICAgICAgICAgICAgICA8am91cm5hbF90aXRsZT5KLiBJbnRlZ3IuIEJpb2luZm9ybS48L2pvdXJuYWxfdGl0bGU+DQogICAgICAgICAgICAgIDxhdXRob3I+QmVyZ21hbm48L2F1dGhvcj4NCiAgICAgICAgICAgICAgPHZvbHVtZT4xMjwvdm9sdW1lPg0KICAgICAgICAgICAgICA8Zmlyc3RfcGFnZT4yNjI8L2ZpcnN0X3BhZ2U+DQogICAgICAgICAgICAgIDxjWWVhcj4yMDE1PC9jWWVhcj4NCiAgICAgICAgICAgICAgPGRvaSBwcm92aWRlcj0iY3Jvc3NyZWYiPjEwLjE1MTUvamliLTIwMTUtMjYyPC9kb2k+DQogICAgICAgICAgICAgIDxhcnRpY2xlX3RpdGxlPlNpbXVsYXRpb24gZXhwZXJpbWVudCBkZXNjcmlwdGlvbiBtYXJrdXAgbGFuZ3VhZ2UgKFNFRC1NTCkgTGV2ZWwgMSBWZXJzaW9uIDI8L2FydGljbGVfdGl0bGU+DQogICAgICAgICAgICA8L2NpdGF0aW9uPg0KICAgICAgICAgICAgPGNpdGF0aW9uIGtleT0iMjAxNzAxMDMyMzE1MTI2MjAwMF80NS5EMS5ENDA0LjEwIj4NCiAgICAgICAgICAgICAgPGpvdXJuYWxfdGl0bGU+Si4gSW50ZWdyLiBCaW9pbmZvcm0uPC9qb3VybmFsX3RpdGxlPg0KICAgICAgICAgICAgICA8YXV0aG9yPkJlcmdtYW5uPC9hdXRob3I+DQogICAgICAgICAgICAgIDx2b2x1bWU+MTI8L3ZvbHVtZT4NCiAgICAgICAgICAgICAgPGZpcnN0X3BhZ2U+MjYxPC9maXJzdF9wYWdlPg0KICAgICAgICAgICAgICA8Y1llYXI+MjAxNTwvY1llYXI+DQogICAgICAgICAgICAgIDxkb2kgcHJvdmlkZXI9ImNyb3NzcmVmIj4xMC4xNTE1L2ppYi0yMDE1LTI2MTwvZG9pPg0KICAgICAgICAgICAgICA8YXJ0aWNsZV90aXRsZT5DT01CSU5FIGFyY2hpdmUgc3BlY2lmaWNhdGlvbiB2ZXJzaW9uIDE8L2FydGljbGVfdGl0bGU+DQogICAgICAgICAgICA8L2NpdGF0aW9uPg0KICAgICAgICAgICAgPGNpdGF0aW9uIGtleT0iMjAxNzAxMDMyMzE1MTI2MjAwMF80NS5EMS5ENDA0LjExIj4NCiAgICAgICAgICAgICAgPGpvdXJuYWxfdGl0bGU+Si4gV2ViIFNlbWFudGljczwvam91cm5hbF90aXRsZT4NCiAgICAgICAgICAgICAgPGF1dGhvcj5CZWxoYWpqYW1lPC9hdXRob3I+DQogICAgICAgICAgICAgIDx2b2x1bWU+MzI8L3ZvbHVtZT4NCiAgICAgICAgICAgICAgPGZpcnN0X3BhZ2U+MTY8L2ZpcnN0X3BhZ2U+DQogICAgICAgICAgICAgIDxjWWVhcj4yMDE1PC9jWWVhcj4NCiAgICAgICAgICAgICAgPGRvaSBwcm92aWRlcj0iY3Jvc3NyZWYiPjEwLjEwMTYvai53ZWJzZW0uMjAxNS4wMS4wMDM8L2RvaT4NCiAgICAgICAgICAgICAgPGFydGljbGVfdGl0bGU+VXNpbmcgYSBzdWl0ZSBvZiBvbnRvbG9naWVzIGZvciBwcmVzZXJ2aW5nIHdvcmtmbG93LWNlbnRyaWMgcmVzZWFyY2ggb2JqZWN0czwvYXJ0aWNsZV90aXRsZT4NCiAgICAgICAgICAgIDwvY2l0YXRpb24+DQogICAgICAgICAgICA8Y2l0YXRpb24ga2V5PSIyMDE3MDEwMzIzMTUxMjYyMDAwXzQ1LkQxLkQ0MDQuMTIiPg0KICAgICAgICAgICAgICA8ZG9pPjEwLjExMTEvZmVicy4xMjQzODwvZG9pPg0KICAgICAgICAgICAgPC9jaXRhdGlvbj4NCiAgICAgICAgICAgIDxjaXRhdGlvbiBrZXk9IjIwMTcwMTAzMjMxNTEyNjIwMDBfNDUuRDEuRDQwNC4xMyI+DQogICAgICAgICAgICAgIDxkb2k+MTAuMTAzOC9zZGF0YS4yMDE2LjE4PC9kb2k+DQogICAgICAgICAgICA8L2NpdGF0aW9uPg0KICAgICAgICAgIDwvY2l0YXRpb25fbGlzdD4NCiAgICAgICAgPC9qb3VybmFsX2FydGljbGU+DQogICAgICA8L2pvdXJuYWw+DQogICAgPC9jcm9zc3JlZj4NCiAgPC9kb2lfcmVjb3JkPg0KPC9kb2lfcmVjb3Jkcz4= - http_version: - recorded_at: Mon, 14 Oct 2019 08:15:19 GMT -recorded_with: VCR 2.9.3