diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 34b61a0..80b21c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: docker-publish: name: Docker Build and Publish - if: github.ref_name == 'develop' || startsWith(github.ref, 'refs/tags/v') + if: github.ref_name == 'develop' || startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref_name, 'feature') needs: maven-build runs-on: ubuntu-latest permissions: diff --git a/.vscode/eclipse-java-google-style.xml b/.vscode/eclipse-java-google-style.xml new file mode 100644 index 0000000..0dd7ed5 --- /dev/null +++ b/.vscode/eclipse-java-google-style.xml @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..aeac9eb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "java.configuration.updateBuildConfiguration": "interactive", + "java.compile.nullAnalysis.mode": "automatic", + "java.format.settings.url": ".vscode/eclipse-java-google-style.xml" +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 154ad58..3a3fb18 100644 --- a/pom.xml +++ b/pom.xml @@ -6,8 +6,8 @@ UTF-8 metadig - 2.5.0 - 2.5.0 + 3.0.0 + 3.0.0 4.0.0 @@ -15,7 +15,7 @@ edu.ucsb.nceas metadig-webapp war - 2.5.0 + 3.0.0-SNAPSHOT metadig-webapp diff --git a/src/main/java/edu/ucsb/nceas/mdq/MetadigContextListener.java b/src/main/java/edu/ucsb/nceas/mdq/MetadigContextListener.java index 7bb7674..dd3dcef 100644 --- a/src/main/java/edu/ucsb/nceas/mdq/MetadigContextListener.java +++ b/src/main/java/edu/ucsb/nceas/mdq/MetadigContextListener.java @@ -7,15 +7,24 @@ import javax.servlet.ServletContextListener; import java.io.IOException; import java.util.concurrent.TimeoutException; +import edu.ucsb.nceas.mdqengine.dispatch.Dispatcher; import edu.ucsb.nceas.mdqengine.Controller; +import edu.ucsb.nceas.mdqengine.exception.MetadigException; +@WebListener public class MetadigContextListener implements ServletContextListener { public static Log log = LogFactory.getLog(MetadigContextListener.class); @Override public void contextInitialized(ServletContextEvent servletContextEvent) { - log.debug("Metadig 'contextInitialized' called."); + try { + Dispatcher.setupJep(); + } catch (MetadigException e) { + throw new RuntimeException("Error setting up Jep. Aborting startup.", e); + } + + log.info("Metadig 'contextInitialized' called."); } @Override @@ -26,7 +35,7 @@ public void contextDestroyed(ServletContextEvent servletContextEvent) { try { log.debug("Shutting down controller..."); controller.shutdown(); - log.info("Controller shutdonw successfully."); + log.info("Controller shut down successfully."); } catch (IOException | TimeoutException e) { log.error("Error shutting down metadig controller."); e.printStackTrace(); diff --git a/src/main/java/edu/ucsb/nceas/mdq/rest/ChecksResource.java b/src/main/java/edu/ucsb/nceas/mdq/rest/ChecksResource.java index c5e4db4..bddede7 100644 --- a/src/main/java/edu/ucsb/nceas/mdq/rest/ChecksResource.java +++ b/src/main/java/edu/ucsb/nceas/mdq/rest/ChecksResource.java @@ -18,16 +18,13 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; import javax.ws.rs.core.Variant; import javax.xml.bind.JAXBException; -import com.hp.hpl.jena.shared.ConfigException; import edu.ucsb.nceas.mdqengine.exception.MetadigException; import edu.ucsb.nceas.mdqengine.exception.MetadigStoreException; -import net.sf.saxon.functions.ConstantFunction; import org.apache.commons.configuration2.ex.ConfigurationException; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; @@ -44,31 +41,32 @@ import edu.ucsb.nceas.mdqengine.store.StoreFactory; import edu.ucsb.nceas.mdqengine.serialize.JsonMarshaller; import edu.ucsb.nceas.mdqengine.serialize.XmlMarshaller; +import edu.ucsb.nceas.mdqengine.dispatch.Dispatcher; /** * Root resource (exposed at "checks" path) */ @Path("checks") public class ChecksResource { - - private Log log = LogFactory.getLog(this.getClass()); - - private MDQStore store = null; - - private MDQEngine engine = null; - - public ChecksResource() throws MetadigStoreException { - boolean persist = false; - this.store = StoreFactory.getStore(persist); + + private Log log = LogFactory.getLog(this.getClass()); + + private MDQStore store = null; + + private MDQEngine engine = null; + + public ChecksResource() throws MetadigStoreException { + boolean persist = false; + this.store = StoreFactory.getStore(persist); - try { - this.engine = new MDQEngine(); - this.engine.setStore(this.store); - } catch (MetadigException | IOException | ConfigurationException e) { - log.error(e.getMessage(), e); - } - } - + try { + this.engine = new MDQEngine(); + this.engine.setStore(this.store); + } catch (MetadigException | IOException | ConfigurationException e) { + log.error(e.getMessage(), e); + } + } + /** * Method handling HTTP GET requests. The returned object will be sent * to the client as "text/plain" media type. @@ -78,7 +76,7 @@ public ChecksResource() throws MetadigStoreException { @GET @Produces(MediaType.APPLICATION_JSON) public String listChecks() { - Collection checks = store.listChecks(); + Collection checks = store.listChecks(); return JsonMarshaller.toJson(checks); } @@ -86,45 +84,48 @@ public String listChecks() { @Path("/{id}") @Produces(MediaType.TEXT_XML) public String getCheck(@PathParam("id") String id) throws UnsupportedEncodingException, JAXBException { - Check check = store.getCheck(id); + Check check = store.getCheck(id); return (String) XmlMarshaller.toXml(check, true); } // @POST // @Consumes(MediaType.MULTIPART_FORM_DATA) +// not enabled for security reasons, see: https://github.com/NCEAS/metadig-webapp/issues/21 public boolean createCheck(@FormDataParam("check") InputStream xml) { - Check check = null; - try { - check = (Check) XmlMarshaller.fromXml(IOUtils.toString(xml, "UTF-8"), Check.class); - store.createCheck(check); - } catch (Exception e) { - log.error(e.getMessage(), e); - return false; - } + Check check = null; + try { + check = (Check) XmlMarshaller.fromXml(IOUtils.toString(xml, "UTF-8"), Check.class); + store.createCheck(check); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } return true; } // @PUT // @Path("/{id}") // @Consumes(MediaType.MULTIPART_FORM_DATA) +// not enabled for security reasons, see: https://github.com/NCEAS/metadig-webapp/issues/21 public boolean updateCheck(@PathParam("id") String id, @FormDataParam("check") InputStream xml) throws JAXBException, IOException { - Check check = null; - try { - check = (Check) XmlMarshaller.fromXml(IOUtils.toString(xml, "UTF-8"), Check.class); - store.updateCheck(check); - } catch (Exception e) { - log.error(e.getMessage(), e); - return false; - } + Check check = null; + try { + check = (Check) XmlMarshaller.fromXml(IOUtils.toString(xml, "UTF-8"), Check.class); + store.updateCheck(check); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } return true; } // @DELETE // @Path("/{id}") // @Produces(MediaType.TEXT_PLAIN) +// not enabled for security reasons, see: https://github.com/NCEAS/metadig-webapp/issues/21 public boolean updateCheck(@PathParam("id") String id) { - Check check = store.getCheck(id); - store.deleteCheck(check); + Check check = store.getCheck(id); + store.deleteCheck(check); return true; } @@ -133,51 +134,49 @@ public boolean updateCheck(@PathParam("id") String id) { @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response run( - @PathParam("id") String id, - @FormDataParam("document") InputStream input, - @FormDataParam("systemMetadata") InputStream sysMetaStream, - @Context Request r) throws UnsupportedEncodingException, JAXBException { - - Run run = null; - // include SM if it was provided - SystemMetadata sysMeta = null; - if (sysMetaStream != null) { - try { - sysMeta = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysMetaStream); - } catch (InstantiationException | IllegalAccessException - | IOException | MarshallingException e) { - log.warn("Could not unmarshall SystemMetadata from stream", e); - } - } - try { - Map params = new HashMap(); -// params.putAll(formParams); -// params.remove("id"); -// params.remove("document"); - Check check = store.getCheck(id); - run = engine.runCheck(check, input, params, sysMeta); - store.createRun(run); - } catch (Exception e) { - log.error(e.getMessage(), e); - return Response.serverError().entity(e).build(); - } - - // determine the format of plot to return + @PathParam("id") String id, + @FormDataParam("document") InputStream input, + @FormDataParam("systemMetadata") InputStream sysMetaStream, + @Context Request r) throws UnsupportedEncodingException, JAXBException { + + Run run = null; + // include SM if it was provided + SystemMetadata sysMeta = null; + if (sysMetaStream != null) { + try { + sysMeta = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysMetaStream); + } catch (InstantiationException | IllegalAccessException + | IOException | MarshallingException e) { + log.warn("Could not unmarshall SystemMetadata from stream", e); + } + } + try { + Map params = new HashMap(); + Check check = store.getCheck(id); + run = engine.runCheck(check, input, params, sysMeta); + store.createRun(run); + Dispatcher.getDispatcher("python").close(); + } catch (Exception e) { + log.error(e.getMessage(), e); + return Response.serverError().entity(e).build(); + } + + // determine the format of plot to return String resultString = null; - List vs = - Variant.mediaTypes(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE).build(); - Variant v = r.selectVariant(vs); - if (v == null) { - return Response.notAcceptable(vs).build(); - } else { - MediaType mt = v.getMediaType(); - if (mt.equals(MediaType.APPLICATION_XML_TYPE)) { - resultString = XmlMarshaller.toXml(run, true); - } else { - resultString = JsonMarshaller.toJson(run); - } - } - - return Response.ok(resultString).build(); + List vs = + Variant.mediaTypes(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE).build(); + Variant v = r.selectVariant(vs); + if (v == null) { + return Response.notAcceptable(vs).build(); + } else { + MediaType mt = v.getMediaType(); + if (mt.equals(MediaType.APPLICATION_XML_TYPE)) { + resultString = XmlMarshaller.toXml(run, true); + } else { + resultString = JsonMarshaller.toJson(run); + } + } + + return Response.ok(resultString).build(); } } diff --git a/src/main/java/edu/ucsb/nceas/mdq/rest/SuitesResource.java b/src/main/java/edu/ucsb/nceas/mdq/rest/SuitesResource.java index 92b35aa..573db49 100644 --- a/src/main/java/edu/ucsb/nceas/mdq/rest/SuitesResource.java +++ b/src/main/java/edu/ucsb/nceas/mdq/rest/SuitesResource.java @@ -34,64 +34,63 @@ import edu.ucsb.nceas.mdqengine.model.Suite; import edu.ucsb.nceas.mdqengine.serialize.JsonMarshaller; import edu.ucsb.nceas.mdqengine.serialize.XmlMarshaller; +import edu.ucsb.nceas.mdqengine.dispatch.Dispatcher; /** * Root resource (exposed at "suites" path) */ @Path("suites") public class SuitesResource { - - private Log log = LogFactory.getLog(this.getClass()); + + private Log log = LogFactory.getLog(this.getClass()); private static Controller metadigCtrl = null; - - public SuitesResource() {} - + + public SuitesResource() {} + /** - * Method handling HTTP GET requests. The returned object will be sent - * to the client as "text/plain" media type. + * Method handling HTTP GET requests. The returned object will be sent to the client as + * "text/plain" media type. * * @return String that will be returned as a text/plain response. */ @GET @Produces(MediaType.APPLICATION_JSON) public String listSuites() { - boolean persist = true; + boolean persist = false; MDQStore store = null; - MDQEngine engine = null; try { store = StoreFactory.getStore(persist); - engine = new MDQEngine(); - } catch (MetadigException | IOException | ConfigurationException e) { + } catch (MetadigException e) { InternalServerErrorException ise = new InternalServerErrorException(e.getMessage()); - throw(ise); + throw (ise); } - Collection suites = store.listSuites(); - store.shutdown(); + Collection suites = store.listSuites(); + store.shutdown(); return JsonMarshaller.toJson(suites); } - + @GET @Path("/{id}") @Produces(MediaType.TEXT_XML) - public String getSuite(@PathParam("id") String id) throws UnsupportedEncodingException, JAXBException { - boolean persist = true; + public String getSuite(@PathParam("id") String id) + throws UnsupportedEncodingException, JAXBException { + boolean persist = false; MDQStore store = null; - MDQEngine engine = null; try { store = StoreFactory.getStore(persist); - engine = new MDQEngine(); - } catch (MetadigException | IOException | ConfigurationException e) { + } catch (MetadigException e) { InternalServerErrorException ise = new InternalServerErrorException(e.getMessage()); - throw(ise); + throw (ise); } - Suite suite = store.getSuite(id); + Suite suite = store.getSuite(id); store.shutdown(); return XmlMarshaller.toXml(suite, true); } - -// @POST -// @Consumes(MediaType.MULTIPART_FORM_DATA) + + // @POST + // @Consumes(MediaType.MULTIPART_FORM_DATA) + // not enabled for security reasons, see: https://github.com/NCEAS/metadig-webapp/issues/21 public boolean createSuite(@FormDataParam("suite") InputStream xml) { boolean persist = true; MDQStore store = null; @@ -101,25 +100,27 @@ public boolean createSuite(@FormDataParam("suite") InputStream xml) { engine = new MDQEngine(); } catch (MetadigException | IOException | ConfigurationException e) { InternalServerErrorException ise = new InternalServerErrorException(e.getMessage()); - throw(ise); + throw (ise); } - Suite suite = null; - try { - suite = (Suite) XmlMarshaller.fromXml(IOUtils.toString(xml, "UTF-8"), Suite.class); - store.createSuite(suite); - } catch (Exception e) { - log.error(e.getMessage(), e); - return false; - } finally { - store.shutdown(); + Suite suite = null; + try { + suite = (Suite) XmlMarshaller.fromXml(IOUtils.toString(xml, "UTF-8"), Suite.class); + store.createSuite(suite); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } finally { + store.shutdown(); } return true; } - -// @PUT -// @Path("/{id}") -// @Consumes(MediaType.MULTIPART_FORM_DATA) - public boolean updateSuite(@PathParam("id") String id, @FormDataParam("suite") InputStream xml) throws JAXBException, IOException { + + // @PUT + // @Path("/{id}") + // @Consumes(MediaType.MULTIPART_FORM_DATA) + // not enabled for security reasons, see: https://github.com/NCEAS/metadig-webapp/issues/21 + public boolean updateSuite(@PathParam("id") String id, @FormDataParam("suite") InputStream xml) + throws JAXBException, IOException { boolean persist = true; MDQStore store = null; MDQEngine engine = null; @@ -128,24 +129,25 @@ public boolean updateSuite(@PathParam("id") String id, @FormDataParam("suite") I engine = new MDQEngine(); } catch (MetadigException | IOException | ConfigurationException e) { InternalServerErrorException ise = new InternalServerErrorException(e.getMessage()); - throw(ise); + throw (ise); } - Suite suite = null; - try { - suite = (Suite) XmlMarshaller.fromXml(IOUtils.toString(xml, "UTF-8"), Suite.class); - store.updateSuite(suite); - } catch (Exception e) { - log.error(e.getMessage(), e); - return false; - } finally { - store.shutdown(); + Suite suite = null; + try { + suite = (Suite) XmlMarshaller.fromXml(IOUtils.toString(xml, "UTF-8"), Suite.class); + store.updateSuite(suite); + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } finally { + store.shutdown(); } return true; } - -// @DELETE -// @Path("/{id}") -// @Produces(MediaType.TEXT_PLAIN) + + // @DELETE + // @Path("/{id}") + // @Produces(MediaType.TEXT_PLAIN) + // not enabled for security reasons, see: https://github.com/NCEAS/metadig-webapp/issues/21 public boolean deleteSuite(@PathParam("id") String id) { boolean persist = true; MDQStore store = null; @@ -155,33 +157,37 @@ public boolean deleteSuite(@PathParam("id") String id) { engine = new MDQEngine(); } catch (MetadigException | IOException | ConfigurationException e) { InternalServerErrorException ise = new InternalServerErrorException(e.getMessage()); - throw(ise); + throw (ise); } - Suite suite = store.getSuite(id); - store.deleteSuite(suite); - store.shutdown(); + Suite suite = store.getSuite(id); + store.deleteSuite(suite); + store.shutdown(); return true; } - + @POST @Path("/{id}/run") @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - public Response run( - @PathParam("id") String id, // id is the metadig suite id - @FormDataParam("document") InputStream input, // the input metadata document - @FormDataParam("systemMetadata") InputStream sysMetaStream, // the system metadata for the input metadata document - @FormDataParam("priority") String priority, // the priority to enqueue the metadig engine request with ("high", "medium", "low") - @Context Request r) throws UnsupportedEncodingException, JAXBException { + public Response run(@PathParam("id") String id, // id is the metadig suite id + @FormDataParam("document") InputStream input, // the input metadata document + @FormDataParam("systemMetadata") InputStream sysMetaStream, // the system metadata for + // the input metadata + // document + @FormDataParam("priority") String priority, // the priority to enqueue the metadig + // engine request with + // ("high", "medium", "low") + @Context Request r) throws UnsupportedEncodingException, JAXBException { boolean persist = true; MDQStore store = null; MDQEngine engine = null; - if(priority == null) priority = "low"; - Run run = null; + if (priority == null) + priority = "low"; + Run run = null; String resultString = null; - // Copy the sysmeta input stream because we need to read it twice + // Copy the sysmeta input stream because we need to read it twice ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] streamData = null; @@ -201,27 +207,29 @@ public Response run( ByteArrayInputStream sysmetaStream = new ByteArrayInputStream(streamData); - SystemMetadata sysMeta = null; - // Read sysmeta input stream to get values to log and pass to the controller - if (sysMetaStream != null) { - try { - sysMeta = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmetaStream); - } catch (InstantiationException | IllegalAccessException - | IOException | MarshallingException e) { - log.warn("Could not unmarshall SystemMetadata from stream", e); - } - } + SystemMetadata sysMeta = null; + // Read sysmeta input stream to get values to log and pass to the controller + if (sysMetaStream != null) { + try { + sysMeta = + TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmetaStream); + } catch (InstantiationException | IllegalAccessException | IOException + | MarshallingException e) { + log.warn("Could not unmarshall SystemMetadata from stream", e); + } + } - // If the request is identifying itself as 'high', then process it now, otherwise send it + // If the request is identifying itself as 'high', then process it now, + // otherwise send it // to the processing queue. - if(priority.equals("high")) { + if (priority.equals("high")) { try { store = StoreFactory.getStore(persist); engine = new MDQEngine(); } catch (MetadigException | IOException | ConfigurationException e) { InternalServerErrorException ise = new InternalServerErrorException(e.getMessage()); - throw(ise); + throw (ise); } try { log.info("Running suite " + id + " for pid " + sysMeta.getIdentifier().getValue()); @@ -229,6 +237,7 @@ public Response run( Suite suite = store.getSuite(id); run = engine.runSuite(suite, input, params, sysMeta); store.createRun(run); + Dispatcher.getDispatcher("python").close(); } catch (Exception e) { log.error(e.getMessage(), e); return Response.serverError().entity(e).build(); @@ -237,8 +246,9 @@ public Response run( } // determine the format of plot to return - List vs = - Variant.mediaTypes(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE).build(); + List vs = Variant + .mediaTypes(MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE) + .build(); Variant v = r.selectVariant(vs); if (v == null) { return Response.notAcceptable(vs).build(); @@ -252,7 +262,7 @@ public Response run( } } else { try { - if(metadigCtrl == null) { + if (metadigCtrl == null) { metadigCtrl = Controller.getInstance(); // Start the controller if it has not already been started. if (!metadigCtrl.getIsStarted()) { @@ -264,7 +274,8 @@ public Response run( return Response.serverError().entity(e).build(); } - // Check if the metadig-engine controller has been started. If not, return a message. + // Check if the metadig-engine controller has been started. If not, return a + // message. // TODO: return a properly formatted XML error message if (!metadigCtrl.getIsStarted()) { return Response.serverError().build(); @@ -276,15 +287,18 @@ public Response run( DateTime requestDateTime = new DateTime(); NodeReference dataSource = sysMeta.getOriginMemberNode(); String metadataPid = sysMeta.getIdentifier().getValue(); - log.info("Queue generation request of quality document for: " + dataSource.getValue() + ", PID: " + metadataPid + ", " + id + ", " + requestDateTime.toString()); - metadigCtrl.processQualityRequest(dataSource.getValue(), metadataPid, input, id, "", requestDateTime, sysmetaStream2); + log.info("Queue generation request of quality document for: " + + dataSource.getValue() + ", PID: " + metadataPid + ", " + id + ", " + + requestDateTime.toString()); + metadigCtrl.processQualityRequest(dataSource.getValue(), metadataPid, input, id, "", + requestDateTime, sysmetaStream2); } catch (Exception e) { log.error(e.getMessage(), e); return Response.serverError().entity(e).build(); } } - return Response.ok().build(); + return Response.ok(resultString).build(); } - + } diff --git a/src/test/resources/test-api.sh b/src/test/resources/test-api.sh new file mode 100644 index 0000000..405fe2a --- /dev/null +++ b/src/test/resources/test-api.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# API endpoint URL for testing a check or suite +check_url="http://localhost:8080/metadig-webapp-3.0.0/checks/resource.keywords.controlled-2.0.0/run/" +suite_url="http://localhost:8080/metadig-webapp-3.0.0/suites/FAIR-suite-0.4.0/run/" +# Headers +headers=( + "Content-Type: multipart/mixed" +) + +# Make the API request using curl +curl -X POST "$suite_url" \ + --header 'Content-Type: multipart/form-data; boundary=---------BOUNDARY' \ + --data-binary @testfile.txt + diff --git a/src/test/resources/testfile.txt b/src/test/resources/testfile.txt new file mode 100644 index 0000000..1f751c7 --- /dev/null +++ b/src/test/resources/testfile.txt @@ -0,0 +1,1220 @@ + +-----------BOUNDARY +Content-Disposition: form-data; name="priority" +Content-Type: text/plain + +high +-----------BOUNDARY +Content-Disposition: form-data; name="document" +Content-Type: application/xml;charset=UTF-8 + + + + + Fairbanks sulfate isotope measurements during ALPACA (2022) + + + Allison + Moon + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + allimoon@uw.edu + https://orcid.org/0000-0002-1648-4869 + + + + Ursula + Jongebloed + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + + + + Kayane + Dingilian + + – School of Earth and Atmospheric Sciences, Georgia Institute of Technology, Atlanta + Postdoctoral researcher + + + + Andrew + Schauer + + Department of Earth and Space Sciences, University of Washington, Seattle + Research Scientist + + + + Yuk-Chun + Chan + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + + + + Meeta + Cesler-Maloney + + Department of Chemistry, Biochemistry, and Geophysical Institute, University of Alaska Fairbanks + Graduate Student + + + + William + Simpson + + Department of Chemistry, Biochemistry, and Geophysical Institute, University of Alaska Fairbanks + Professor + + + + Rodney + Weber + + – School of Earth and Atmospheric Sciences, Georgia Institute of Technology, Atlanta + Professor + + + + Ling + Tsiang + + Department of Atmospheric Sciences, University of Washington, Seattle + Undergraduate Student + + + + Fouad + Yazbeck + + Department of Atmospheric Sciences, University of Washington, Seattle + Undergraduate Student + + + + Shuting + Zhai + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + + + + Alanna + Wedum + + Department of Atmospheric Sciences, University of Washington, Seattle + Undergraduate Student + + + + Alexander + Turner + + Department of Atmospheric Sciences, University of Washington, Seattle + Professor + + + + Sarah + Albertin + + IGE, Univ. Grenoble Alpes, CNRS, INRAE, IRD + Graduate Student + + + + Slimane + Bekki + + – LATMOS/IPSL, Sorbonne Université, UVSQ, CNRS + Research Scientist + + + + Joël + Savarino + + IGE, Univ. Grenoble Alpes, CNRS, INRAE, IRD + Senior Scientist + + + + Konstantin + Gribanov + + Climate and Environment Physics Laboratory, Ural Federal University + Senior Researcher + + + + Kerri + Pratt + + Department of Chemistry, University of Michigan, Ann Arbor + Professor + + + + Emily + Costa + + Department of Chemistry, University of Michigan, Ann Arbor + Graduate Student + + + + Cort + Anastasio + + - Department of Land, Air, & Water Resources, University of California, Davis + Professor + + + + Michael + Sunday + + - Department of Land, Air, & Water Resources, University of California, Davis + Postdoctoral researcher + + + + Laura + Heinlein + + - Department of Land, Air, & Water Resources, University of California, Davis + Graduate Student + + + + Jingqiu + Mao + + Department of Chemistry, Biochemistry, and Geophysical Institute, University of Alaska Fairbanks + Professor + + + + Becky + Alexander + + Department of Atmospheric Sciences, University of Washington, Seattle + Professor + beckya@uw.edu + + 2023 + + Within and surrounding high-latitude cities, poor air quality disturbs Arctic ecosystems, influences climate, and harms human health. The Fairbanks North Star Borough has wintertime particulate matter (PM) concentrations that exceed the Environmental Protection Agency’s (EPA) threshold for public health. Particulate sulfate (SO42-) is the most abundant inorganic species and contributes approximately 20% of the total PM mass in Fairbanks, but air quality models underestimate observed sulfate concentrations. Here we quantify sulfate sources using size-resolved δ34S(SO42-), δ18O(SO42-), and Δ17O(SO42-) of particulate sulfate in Fairbanks from January 18th to February 25th, 2022 using a Bayesian isotope mixing model. + This data contains sulfur and oxygen isotope measurements for size-resolved filter samples collected during the Alaskan Layered Pollution and Chemical Analysis field campaign in 2022. Ambient concentrations of SO2, HMS, non-HMS S(IV), SO4, and the sulfur oxidation ratio are also included. Finally, the median fractional contributions of each oxidation pathway calculated in the Bayesian isotope mixing model are included with their 95% confidence interval. + + + sulfate + isotope + aerosol + air quality + haze + ALPACA + Fairbanks + Alaska + None + + + This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/. + + + + Community Technical College in downtown Fairbanks + + -147.4919 + -147.4919 + 65.1256 + 65.1256 + + + + + + 2022-01-18 + + + + 2022-02-25 + + + + + + + http://www.w3.org/ns/dcat#theme + https://purl.dataone.org/odo/ADCAD_00034 + + + http://www.w3.org/ns/dcat#theme + https://purl.dataone.org/odo/ADCAD_00039 + + + http://purl.dataone.org/odo/SENSO_00000005 + http://purl.dataone.org/odo/SENSO_00000002 + + + + Allison + Moon + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + allimoon@uw.edu + https://orcid.org/0000-0002-1648-4869 + + + + Becky + Alexander + + Department of Atmospheric Sciences, University of Washington, Seattle + Professor + beckya@uw.edu + + + NSF Arctic Data Center + support@arcticdata.io + http://arcticdata.io + Q77285095 + + + + +
+ Ethical Research Practices + Collection of this data did not involve human subjects or animals. Throughout the field campaign, Fairbanks town hall meetings were held to communicate the research being done during ALPACA with the community. These results will be publically available both through peer-reviewed publications and community outreach materials. +
+
+
+ + + A Volumetric Flow Controlled Particulate Sampling System (TE-5170) with a 4-stage cascade impactor (TE-230) was used to collect 24-hr size-resolved aerosol samples at Fairbanks Community Technical College (CTC) (64.84064°N, 147.72677°W) between January 17th to February 25th, 2022. Size-resolved bins were determined by calculating the particle size cut-off (Dp,50) at 50% collection efficiency using the corrected flow rate in each sample. Two filter samples were collected for one week each at the Poker Flat Research range (65.1256° N, 147.4919° W), a relatively clean site 46 km north of Fairbanks, to represent a two-week average of background sulfate. Atmospheric particles were collected using a high-volume sampler (Digitel, DH77, TSP inlet, 1 m3 min-1) on pre-combusted quartz filters (Whatman 150nm-diameter). + + + + + https://google.com Isotope samples were prepared for silver salt pyrolysis as described in Schauer et al. and Geng et al.54,55 Briefly, the filtrate was neutralized by converting anions to sodium-form with an offline cation exchange resin (AG 50W-X8 Resin from Bio-Rad). This converts sulfuric acid (H2SO4) to sodium sulfate (Na2SO4), which prevents sample loss due to evaporation. This step is followed by the removal of soluble organics by adding 30% H2O2 and drying in a MiVAc Duo concentrator. Sulfate was separated from other ions in the sample matrix in a Dionex ICS-2000 before being converted to Ag2SO4 using Ag+-charged cation-exchange resin as described in Geng et al. + + + + + Oxygen isotope measurements were performed on a Finnegan MAT253 isotope ratio mass spectrometer using the same configuration as Geng et al.55 Oxygen isotope measurements were corrected for isotopic exchange with quartz and conversion of HMS and non-HMS S(IV) to sulfate during sample preparation (see supplement section 1.4.1). Sulfur isotope composition was measured using a separate Finnegan MAT253 isotope ratio mass spectrometer with the same configuration as Jongebloed et al.56 δ34S values were normalized to the Vienna Canyon Diablo Troilite (VCDT) scale using four in-house reference materials that are regularly calibrated against the international reference materials IAEA-S-1, IAEA-S-3, and NBS-127. A sulfur isotope correction for sulfate formed from HMS and S(IV) during sample processing was estimated as described in section 1.4.2. The δ34S composition of Fairbanks fuel oils #1 and #2 aquired during winter 2022 was measured by combusting 6 μL of fuel oil in a 50 μL tin capsule packed with tin powder. A source signature for δ34Semission was calculated using the δ34S measurements for fuel oil #1 (+3.7±0.6‰) and fuel oil #2 (+4.9±0.1‰) and weighing the values by sulfur content (896 and 2,053 ppmv, respectively) and domestic use (33% and 67%, respectively) (Table S4)19. This yielded a δ34Semission signature of +4.7 (±0.6)‰. The analytical error of the measurements (±0.8‰, ±0.2‰, and ±1.0‰ for δ18O, Δ17O, and δ34S, respectively) was estimated from duplicate sample analysis (performed on 30% of the Fairbanks samples) and replicate measurements of standards in quartz and silver capsules. The fully propagated error including isotopic corrections for the three measurements are: δ18O (±1.9‰), Δ17O (±0.4‰), and δ34S (±1.2‰). + + + + + We developed an isotope mixing model to investigate the contributions of primary sulfate and five secondary sulfate formation pathways (H2O2, O3, TMI-O2, OH, and NO2). The model inputs are the δ18O(SO42−), Δ17O(SO42−), and δ34S(SO42−) observations. We assumed the observed δ18O(SO42−), Δ17O(SO42−), and δ34S(SO42−) follow a multivariate Gaussian distribution. We used a Dirichlet distribution as the prior for the fractional contributions such that each fraction is in the interval [0,1] and all fractions sum to 1. Markov Chain Monte Carlo was used to calculate the fractional contributions of each sulfate formation pathway for each sample and estimate the uncertainty by providing a 95% confidence interval. + + + + + Schauer, A. J., Kunasek, S. A., Sofen, E. D., Erbland, J., Savarino, J., Johnson, B. W., Amos, H. M., Shaheen, R., Abaunza, M., Jackson, T. L., Thiemens, M. H., & Alexander, B. (2012). Oxygen isotope exchange with quartz during pyrolysis of silver sulfate and silver nitrate: Oxygen isotope exchange during pyrolysis of Ag 2 SO 4 and AgNO 3. Rapid Communications in Mass Spectrometry, 26(18), 2151–2157. https://doi.org/10.1002/rcm.6332 + Geng, L., Schauer, A. J., Kunasek, S. A., Sofen, E. D., Erbland, J., Savarino, J., Allman, D. J., Sletten, R. S., & Alexander, B. (2013). Analysis of oxygen-17 excess of nitrate and sulfate at sub-micromole levels using the pyrolysis method: Analysis of oxygen-17 excess of nitrate and sulfate. Rapid Communications in Mass Spectrometry, 27(21), 2411–2419. https://doi.org/10.1002/rcm.6703 + + + + + + A Volumetric Flow Controlled Particulate Sampling System (TE-5170) with a 4-stage cascade impactor (TE-230) was used to collect 24-hr size-resolved aerosol samples at Fairbanks Community Technical College (CTC) (64.84064°N, 147.72677°W) between January 17th to February 25th, 2022. Size-resolved bins were determined by calculating the particle size cut-off (Dp,50) at 50% collection efficiency using the corrected flow rate in each sample (equation S1 in the Supporting Information). For each collection period, filters were combined to form three-size bins: particle diameters < 0.7 μm (PM<0.7), 0.7-2.5 μm (PM0.7-2.5), and 2.5-10 μm (PM2.5-10). Both PM0.7 and PM0.7-2.5 fall within the EPA-regulated fine particle range deemed PM2.5, but are analyzed in separate size bins here. Filter samples were collected daily between 9:30 AM to 9:00 AM the following day except for one exceptionally polluted period between January 31st to February 3rd when the filters were changed twice per day at approximately 9:30 AM and 5 PM local time. + + + + No sampling description provided. + + +
+ + Fairbanks sulfate isotope measurements during ALPACA + + + Allison + Moon + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + principalInvestigator + + + + Ursula + Jongebloed + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + principalInvestigator + + + + Kayane + Dingilian + + – School of Earth and Atmospheric Sciences, Georgia Institute of Technology, Atlanta + Postdoctoral researcher + principalInvestigator + + + + Andrew + Schauer + + Department of Earth and Space Sciences, University of Washington, Seattle + Research Scientist + principalInvestigator + + + + Yuk-Chun + Chan + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + principalInvestigator + + + + Meeta + Cesler-Maloney + + Department of Chemistry, Biochemistry, and Geophysical Institute, University of Alaska Fairbanks + Graduate Student + principalInvestigator + + + + William + Simpson + + Department of Chemistry, Biochemistry, and Geophysical Institute, University of Alaska Fairbanks + Professor + principalInvestigator + + + + Rodney + Weber + + – School of Earth and Atmospheric Sciences, Georgia Institute of Technology, Atlanta + Professor + principalInvestigator + + + + Ling + Tsiang + + Department of Atmospheric Sciences, University of Washington, Seattle + Undergraduate Student + principalInvestigator + + + + Fouad + Yazbeck + + Department of Atmospheric Sciences, University of Washington, Seattle + Undergraduate Student + principalInvestigator + + + + Shuting + Zhai + + Department of Atmospheric Sciences, University of Washington, Seattle + Graduate Student + principalInvestigator + + + + Alanna + Wedum + + Department of Atmospheric Sciences, University of Washington, Seattle + Undergraduate Student + principalInvestigator + + + + Alexander + Turner + + Department of Atmospheric Sciences, University of Washington, Seattle + Professor + principalInvestigator + + + + Sarah + Albertin + + IGE, Univ. Grenoble Alpes, CNRS, INRAE, IRD + Graduate Student + principalInvestigator + + + + Slimane + Bekki + + – LATMOS/IPSL, Sorbonne Université, UVSQ, CNRS + Research Scientist + principalInvestigator + + + + Joël + Savarino + + IGE, Univ. Grenoble Alpes, CNRS, INRAE, IRD + Senior Scientist + principalInvestigator + + + + Konstantin + Gribanov + + Climate and Environment Physics Laboratory, Ural Federal University + Senior Researcher + principalInvestigator + + + + Kerri + Pratt + + Department of Chemistry, University of Michigan, Ann Arbor + Professor + principalInvestigator + + + + Emily + Costa + + Department of Chemistry, University of Michigan, Ann Arbor + Graduate Student + principalInvestigator + + + + Cort + Anastasio + + - Department of Land, Air, & Water Resources, University of California, Davis + Professor + principalInvestigator + + + + Michael + Sunday + + - Department of Land, Air, & Water Resources, University of California, Davis + Postdoctoral researcher + principalInvestigator + + + + Laura + Heinlein + + - Department of Land, Air, & Water Resources, University of California, Davis + Graduate Student + principalInvestigator + + + + Jingqiu + Mao + + Department of Chemistry, Biochemistry, and Geophysical Institute, University of Alaska Fairbanks + Professor + principalInvestigator + + + + Becky + Alexander + + Department of Atmospheric Sciences, University of Washington, Seattle + Professor + principalInvestigator + + + The National Oceanic and Atmospheric Administration (OAR)in the AC4 - Urban atmosphere in a warming climate: chemistry, carbon and composition division. + 0124733 + Fairbanks sulfate isotope measurements during ALPACA + + + + Moon_et_al_isotope_data.csv + Isotope data + + Moon_et_al_isotope_data.csv + 44286 + 629095bed85261d7587fbb79c24d98d7 + + + 1 + + + column + + , + + + + + + https://cn.dataone.org/cn/v2/resolve/urn:uuid:3a6f9c5e-3c7b-4ada-819e-e00ec19053cb + + + + + + Date + Date of measurement. Multiple date format included. + + + DD/MM and PM period + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00002043 + + + + δ34S(‰) + δ34 S is calculated using the ratio of 34S/32S in the sample over the ratio of Vienna Canyon Diablo Troilite (VCDT). The unit is permille (‰). + + + + permil + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + δ18O(‰) + δ18 O is calculated using the ratio of 18O/16O compared to the ratio found in Vienna Standard Mean Ocean water (VSMOW). The unit is permille (‰). + + + + permil + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00001677 + + + + Δ17O(‰) + ∆17 O is calculated using the following equation: +∆17 O(SO4)= δ17 O(SO4 )-0.52∙(δ18 O(SO4)) +where d17O is calculated using the ratio of 17O/16O compared to the ratio found in Vienna Standard Mean Ocean water (VSMOW). The unit is permille (‰). + + + + permil + + + real + + + + + + SO2 (umol/m3) + Ambient concentrations of Sulfur dioxide in umol/m3. + + + + millimolePerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000662 + + + + SOR (SO4/SO2+SO4+HMS+non-HMS SIV) + SOR is the sulfur oxidation ratio. It's the molar concentration of SO4 over the molar concentrations of SO2, HMS, non-HMS S(IV), and SO4. + + + + dimensionless + + + real + + + + + + SO4_PM0.7_ug/m3 + The measurement of particulate matter 0.7 of Sulfate in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00002156 + + + + SO4_PM0.7-2.5_ug/m3 + The measurement of particulate matter 0.7 - 2.5 of Sulfate in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00002156 + + + + SO4_PM2.5-PM10_ug/m3 + The measurement of particulate matter 2.5 - 10 of Sulfate in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00002156 + + + + Non-HMS_SIV_PM0.7_ug/m3 + The concentration of PM 0.7 non- hydroxymethanesulfonate S(IV) in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000512 + + + + Non-HMS_SIV_PM0.7-2.5_ug/m3 + The concentration of PM 0.7-2.5 non- hydroxymethanesulfonate S(IV) in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000512 + + + + Non-HMS_SIV_PM2.5-PM10_ug/m3 + The concentration of PM 2.5-10 non- hydroxymethanesulfonate S(IV) in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000512 + + + + HMS_PM0.7_ug/m3 + The concentration of PM 0.7 hydroxymethanesulfonate in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000512 + + + + HMS_PM0.7-2.5_ug/m3 + The concentration of PM 0.7-2.5 hydroxymethanesulfonate in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000512 + + + + HMS_PM2.5-PM10_ug/m3 + The concentration of PM 2.5-10 hydroxymethanesulfonate in ug/m3. + + + + microgramPerMeterCubed + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000512 + + + + primary_median_fraction + The median percentage of total sulfate from the primary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + OH_median_fraction + The median percentage of total sulfate from the OH secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + H2O2_median_fraction + The median percentage of total sulfate from the H2O2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + TMI_median_fraction + The median percentage of total sulfate from the TMI-O2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + O3_median_fraction + The median percentage of total sulfate from the O3 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + NO2_median_fraction + The median percentage of total sulfate from the NO2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + primary_97.5th_percentile_fraction + The 97.5 percentile percentage of total sulfate from the primary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + OH_97.5th_percentile_fraction + The 97.5 percentile percentage of total sulfate from the OH secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + H2O2_97.5th_percentile_fraction + The 97.5 percentile percentage of total sulfate from the H2O2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + TMI_97.5th_percentile_fraction + The 97.5 percentile percentage of total sulfate from the TMI-O2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + O3_97.5th_percentile_fraction + The 97.5 percentile percentage of total sulfate from the O3 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + NO2_97.5th_percentile_fraction + The 97.5 percentile percentage of total sulfate from the NO2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + primary_2.5th_percentile_fraction + The 2.5 percentile percentage of total sulfate from the primary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + OH2.5th_percentile_fraction + The 2.5 percentile percentage of total sulfate from the OH secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + H2O22.5th_percentile_fraction + The 2.5 percentile percentage of total sulfate from the H2O2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + TMI2.5th_percentile_fraction + The 2.5 percentile percentage of total sulfate from the TMI-O2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + O32.5th_percentile_fraction + The 2.5 percentile percentage of total sulfate from the O3 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + NO2_2.5th_percentile_fraction + The 2.5 percentile percentage of total sulfate from the NO2 secondary sulfate formation pathway. + + + + dimensionless + + + real + + + + + http://ecoinformatics.org/oboe/oboe.1.2/oboe-core.owl#containsMeasurementsOfType + http://purl.dataone.org/odo/ECSO_00000629 + + + + +
+ + + + + microgram per meter cubed + + + + +
+-----------BOUNDARY +Content-Disposition: form-data; name="systemMetadata" +Content-Type: application/xml;charset=UTF-8 + + + + 0 + urn:uuid:6a04c674-61ba-4a36-bdc0-5585f1fce2d0 + https://eml.ecoinformatics.org/eml-2.2.0 + 61569 + 881bf599ca27fbf538444830408e0eab + http://orcid.org/0000-0003-4703-1974 + http://orcid.org/0000-0002-1648-4869 + + + http://orcid.org/0000-0003-4703-1974 + read + write + changePermission + + + CN=arctic-data-admins,DC=dataone,DC=org + read + write + changePermission + + + public + read + + + + false + 2023-11-22T20:51:11.883+00:00 + 2023-11-22T20:51:11.883+00:00 + urn:node:mnTestARCTIC + urn:node:mnTestARCTIC + Fairbanks_sulfate_isotope_measurements_during_ALPA.xml + +-----------BOUNDARY-- +