+sub output_with_http_headers($$$$;$) {
+ my ( $query, $cookie, $data, $content_type, $status ) = @_;
+ $status ||= '200 OK';
+
+ my %content_type_map = (
+ 'html' => 'text/html',
+ 'js' => 'text/javascript',
+ 'json' => 'application/json',
+ 'xml' => 'text/xml',
+ # NOTE: not using application/atom+xml or application/rss+xml because of
+ # Internet Explorer 6; see bug 2078.
+ 'rss' => 'text/xml',
+ 'atom' => 'text/xml'
+ );
+
+ die "Unknown content type '$content_type'" if ( !defined( $content_type_map{$content_type} ) );
+ my $options = {
+ type => $content_type_map{$content_type},
+ status => $status,
+ charset => 'UTF-8',
+ Pragma => 'no-cache',
+ 'Cache-Control' => 'no-cache',
+ };
+ $options->{cookie} = $cookie if $cookie;
+ if ($content_type eq 'html') { # guaranteed to be one of the content_type_map keys, else we'd have died
+ $options->{'Content-Style-Type' } = 'text/css';
+ $options->{'Content-Script-Type'} = 'text/javascript';
+ }
+ # remove SUDOC specific NSB NSE
+ $data =~ s/\x{C2}\x{98}|\x{C2}\x{9C}/ /g;
+ $data =~ s/\x{C2}\x{88}|\x{C2}\x{89}/ /g;
+ print $query->header($options), $data;
+}
+
+sub output_html_with_http_headers ($$$;$) {
+ my ( $query, $cookie, $data, $status ) = @_;
+ $data =~ s/\&\;amp\; /\&\; /;
+ output_with_http_headers( $query, $cookie, $data, 'html', $status );
+}
+
+sub is_ajax () {
+ my $x_req = $ENV{HTTP_X_REQUESTED_WITH};
+ return ( $x_req and $x_req =~ /XMLHttpRequest/i ) ? 1 : 0;