From c47cad2c8f804050d3abb669a30502479a0386c6 Mon Sep 17 00:00:00 2001 From: Frank Greguska Date: Thu, 25 May 2017 15:48:41 -0700 Subject: [PATCH 01/33] method no longer throws any exceptions. wrapped parsing of log line in try block that will issue a warning if a log line cant be parsed but will allow processing to continue. --- .../jpl/mudrod/weblog/structure/FtpLog.java | 66 +++++++------------ 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/FtpLog.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/FtpLog.java index 61b2554..5ddc717 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/FtpLog.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/FtpLog.java @@ -14,69 +14,51 @@ package gov.nasa.jpl.mudrod.weblog.structure; import com.google.gson.Gson; - import gov.nasa.jpl.mudrod.weblog.pre.ImportLogFile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.io.IOException; import java.io.Serializable; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - * This class represents an Apache access log line. See - * http://httpd.apache.org/docs/2.2/logs.html for more details. + * This class represents an FTP access log line. */ public class FtpLog extends WebLog implements Serializable { private static final Logger LOG = LoggerFactory.getLogger(ImportLogFile.class); - - public static String parseFromLogLine(String log) throws IOException, ParseException { - String ip = log.split(" +")[6]; + public static String parseFromLogLine(String log) { - String time = log.split(" +")[1] + ":" + log.split(" +")[2] + ":" + log.split(" +")[3] + ":" + log.split(" +")[4]; - - time = SwithtoNum(time); - SimpleDateFormat formatter = new SimpleDateFormat("MM:dd:HH:mm:ss:yyyy"); - Date date = null; try { - date = formatter.parse(time); - } catch (ParseException e) { - LOG.error("Error whilst parsing ftp log [{}]. ", log, e); - } - - String bytes = log.split(" +")[7]; + String ip = log.split(" +")[6]; - String request = log.split(" +")[8].toLowerCase(); + String time = log.split(" +")[1] + ":" + log.split(" +")[2] + ":" + log.split(" +")[3] + ":" + log.split(" +")[4]; - if (!request.contains("/misc/") && !request.contains("readme") && date != null) { - FtpLog ftplog = new FtpLog(); - ftplog.LogType = "ftp"; - ftplog.IP = ip; - ftplog.Request = request; - ftplog.Bytes = Double.parseDouble(bytes); + time = SwithtoNum(time); + SimpleDateFormat formatter = new SimpleDateFormat("MM:dd:HH:mm:ss:yyyy"); + Date date = formatter.parse(time); - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'"); - ftplog.Time = df.format(date); - // ftplog.Time = date; + String bytes = log.split(" +")[7]; - Gson gson = new Gson(); - String lineJson = gson.toJson(ftplog); + String request = log.split(" +")[8].toLowerCase(); - return lineJson; - } + if (!request.contains("/misc/") && !request.contains("readme")) { + FtpLog ftplog = new FtpLog(); + ftplog.LogType = "ftp"; + ftplog.IP = ip; + ftplog.Request = request; + ftplog.Bytes = Double.parseDouble(bytes); - return "{}"; - } + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'"); + ftplog.Time = df.format(date); - public static boolean checknull(WebLog s) { - if (s == null) { - return false; + return new Gson().toJson(ftplog); + } + } catch (Exception e) { + LOG.warn("Error parsing ftp log line [{}]. Skipping this line.", log, e); } - return true; + return "{}"; } } From 04ea9eaac24fd740a344fbf1b4c26b1c9edb892e Mon Sep 17 00:00:00 2001 From: Lewis John McGibbney Date: Fri, 26 May 2017 00:13:00 -0700 Subject: [PATCH 02/33] ISSUE-65 Integrate ESIP Semantic Portal into MUDROD Relevancy Ranking (#178) * ISSUE-65 Integrate ESIP Semantic Portal into MUDROD Relevancy Ranking * ISSUE-65 Integrate ESIP Semantic Portal into MUDROD Relevancy Ranking * ISSUE-65 Integrate ESIP Semantic Portal into MUDROD Relevancy Ranking * ISSUE-65 Integrate ESIP Semantic Portal into MUDROD Relevancy Ranking * ISSUE-65 Integrate ESIP Semantic Portal into MUDROD Relevancy Ranking --- .../nasa/jpl/mudrod/main/MudrodEngine.java | 2 +- .../nasa/jpl/mudrod/ontology/Ontology.java | 6 +- .../jpl/mudrod/ontology/OntologyFactory.java | 3 +- .../ontology/process/LocalOntology.java | 268 ++-- .../ontology/process/OntologyParser.java | 8 +- .../mudrod/ontology/process/OwlParser.java | 59 +- core/src/main/resources/config.xml | 2 +- core/src/main/resources/ontology/ont.rdf | 1234 ----------------- .../ontology/process/TestLocalOntology.java | 226 +++ .../services/ontology/OntologyResource.java | 19 +- .../search/SearchDatasetDetailResource.java | 4 +- 11 files changed, 408 insertions(+), 1423 deletions(-) delete mode 100644 core/src/main/resources/ontology/ont.rdf create mode 100644 core/src/test/java/gov/nasa/jpl/mudrod/ontology/process/TestLocalOntology.java diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodEngine.java b/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodEngine.java index c0783d5..27dba84 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodEngine.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodEngine.java @@ -145,7 +145,7 @@ private InputStream locateConfig() { InputStream configStream = MudrodEngine.class.getClassLoader().getResourceAsStream("config.xml"); if (configStream != null) { - LOG.info("Loaded config file from " + MudrodEngine.class.getClassLoader().getResource("config.xml").getPath()); + LOG.info("Loaded config file from {}", MudrodEngine.class.getClassLoader().getResource("config.xml").getPath()); } return configStream; diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/Ontology.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/Ontology.java index 08bce09..7bc76fb 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/Ontology.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/Ontology.java @@ -26,16 +26,16 @@ public interface Ontology { /** - * Loading an array URIs which resolve to ontology resources. + * Load an array URIs which resolve to ontology resources. * * @param urls a {@link java.lang.String} containing ontology URIs. */ public void load(String[] urls); /** - * Load a collection of default ontological resources. + * Load a collection of default ontology resources. */ - public void load(); + public void load() ; /** * merge relevant ontology subgraphs into a new subgraph which can diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/OntologyFactory.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/OntologyFactory.java index 4f1d053..f0ef6cd 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/OntologyFactory.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/OntologyFactory.java @@ -64,7 +64,7 @@ public Ontology getOntology() { String ontologyImpl = this.props.getProperty(MudrodConstants.ONTOLOGY_IMPL, "Local"); - LOG.info("Using ontology extension: " + ontologyImpl); + LOG.info("Using ontology extension: {}", ontologyImpl); Ontology ontImpl; switch (ontologyImpl) { case "EsipCOR": @@ -77,7 +77,6 @@ public Ontology getOntology() { ontImpl = new LocalOntology(); break; } - ontImpl.load(); return ontImpl; } diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java index d98d5c2..98de33a 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java @@ -13,11 +13,14 @@ */ package gov.nasa.jpl.mudrod.ontology.process; -import gov.nasa.jpl.mudrod.main.MudrodEngine; import gov.nasa.jpl.mudrod.ontology.Ontology; -import gov.nasa.jpl.mudrod.ontology.OntologyFactory; -import org.apache.commons.cli.*; -import org.apache.jena.ontology.*; +import org.apache.jena.ontology.Individual; +import org.apache.jena.ontology.OntClass; +import org.apache.jena.ontology.OntModel; +import org.apache.jena.ontology.OntModelSpec; +import org.apache.jena.ontology.OntResource; +import org.apache.jena.ontology.Restriction; +import org.apache.jena.rdf.model.AnonId; import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Resource; @@ -25,9 +28,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; import java.io.PrintStream; -import java.util.*; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; /** * The LocalOntology implementation enables us to work with Ontology files @@ -41,13 +50,13 @@ public class LocalOntology implements Ontology { public static final String DELIMITER_SEARCHTERM = " "; - private static final String ONT_DIR = "ontDir"; - private static Hashtable searchTerms = new Hashtable<>(); + private static Map searchTerms = new HashMap<>(); private static OntologyParser parser; private static OntModel ontologyModel; - private static Ontology ontology; - private static Map mAnonIDs = new HashMap<>(); + private Ontology ontology; + private static Map mAnonIDs = new HashMap<>(); private static int mAnonCount = 0; + private List ontArrayList; public LocalOntology() { //only initialize all the static variables @@ -61,6 +70,7 @@ public LocalOntology() { } if (ontologyModel == null) ontologyModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, null); + load(); } /** @@ -69,7 +79,7 @@ public LocalOntology() { * * @return a {@link LocalOntology} */ - public static Ontology getInstance() { + public Ontology getInstance() { if (ontology == null) { ontology = new LocalOntology(); } @@ -77,23 +87,30 @@ public static Ontology getInstance() { } /** - * Load the default ontology directory contained within Mudrod. - * This contains at a minimum SWEET v2.3. + * Load the default sweetAll.owl ontology + * from + * https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl */ @Override public void load() { - File ontDir = new File(LocalOntology.class.getClassLoader().getResource("ontology").getFile()); - - //Fail if the input is not a directory. - if (ontDir.isDirectory()) { - List owlFiles = new ArrayList<>(); - for (File owlFile : ontDir.listFiles()) { - owlFiles.add(owlFile.toString()); - } - //convert to correct iput for ontology loading. - String[] owlArray = new String[owlFiles.size()]; - owlArray = owlFiles.toArray(owlArray); - load(owlArray); + URL ontURL = null; + try { + //TODO aggregate/collection ontologies e.g. ontologies which have ONLY imports, + //such as sweetAll.owl are not currently supported. See Javadoc comment in + // gov.nasa.jpl.mudrod.ontology.process.OwlParser#rootClasses + //ontURL = new URL("https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl"); + ontURL = new URL("https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/reprDataProduct.owl"); + } catch (MalformedURLException e) { + LOG.error("Error when attempting to create URL resource: ", e); + } + ontArrayList = new ArrayList<>(); + try { + ontArrayList.add(ontURL.toURI().toString()); + } catch (URISyntaxException e) { + LOG.error("Error in URL syntax, please check your Ontology resource: ", e); + } + if (!ontArrayList.isEmpty()) { + load(ontArrayList.stream().toArray(String[]::new)); } } @@ -105,33 +122,55 @@ public void load(String[] urls) { for (int i = 0; i < urls.length; i++) { String url = urls[i].trim(); if (!"".equals(url)) - load(ontologyModel, url); + if (LOG.isInfoEnabled()) { + LOG.info("Reading and processing {}", url); + } + load(ontologyModel, url); } - parser.parse(ontologyModel); + parser.parse(ontology, ontologyModel); } private void load(Object m, String url) { try { - if (LOG.isInfoEnabled()) { - LOG.info("Reading {}", url); - } ((OntModel) m).read(url, null, null); + LOG.info("Successfully processed {}", url); } catch (Exception e) { - LOG.error("Failed whilst attempting to read ontology {}", url, e); + LOG.error("Failed whilst attempting to read ontology {}: Error: ", url, e); } } - public static OntologyParser getParser() { + /** + * Get the {@link gov.nasa.jpl.mudrod.ontology.process.OntologyParser} + * implementation being used to process the input ontology resources. + * @return an {@link gov.nasa.jpl.mudrod.ontology.process.OntologyParser} implementation + */ + public OntologyParser getParser() { if (parser == null) { parser = new OwlParser(); } return parser; } + /** + * Return the {@link org.apache.jena.ontology.OntModel} instance + * which created from input ontology resources. + * @return a constructed {@link org.apache.jena.ontology.OntModel} + */ public static OntModel getModel() { return ontologyModel; } + /** + * Return the loaded Ontology resources. + * @return a {@link java.util.List} of resources. + */ + public List getLoadedOntologyResources() { + if (ontArrayList != null) { + return ontArrayList; + } else { + return new ArrayList<>(); + } + } /** * Not yet implemented. */ @@ -142,85 +181,92 @@ public void merge(Ontology o) { /** * Retrieve all subclasses of entity(ies) hashed to searchTerm + * @param entitySearchTerm a query (keywords) for which to obtain + * subclasses. + * @return an {@link java.util.Iterator} containing the subclass as Strings. */ @Override public Iterator subclasses(String entitySearchTerm) { - Map classMap = retrieve(entitySearchTerm); - Map subclasses = new HashMap<>(); + Map classMap = retrieve(entitySearchTerm); + Map subclasses = new HashMap<>(); Iterator iter = classMap.keySet().iterator(); while (iter.hasNext()) { OntResource resource = iter.next(); if (resource instanceof OntClass) { - //get subclasses - for (Iterator i = ((OntClass) resource).listSubClasses(); i.hasNext(); ) { + //get subclasses N.B. we only get direct sub-classes e.g. direct children + //it is possible for us to navigate the entire class tree if we wish, we simply + //need to pass the .listSubClasses(true) boolean parameter. + for (Iterator i = ((OntClass) resource).listSubClasses(); i.hasNext();) { OntResource subclass = (OntResource) i.next(); - for (Iterator j = subclass.listLabels(null); j.hasNext(); ) { + for (Iterator j = subclass.listLabels(null); j.hasNext();) { Literal l = (Literal) j.next(); subclasses.put(l.toString(), "1"); } } //get individuals - for (Iterator i = ((OntClass) resource).listInstances(); i.hasNext(); ) { + for (Iterator i = ((OntClass) resource).listInstances(); i.hasNext(); ) { OntResource subclass = (OntResource) i.next(); - for (Iterator j = subclass.listLabels(null); j.hasNext(); ) { + for (Iterator j = subclass.listLabels(null); j.hasNext();) { Literal l = (Literal) j.next(); subclasses.put(l.toString(), "1"); } } } else if (resource instanceof Individual) { - for (Iterator i = resource.listSameAs(); i.hasNext(); ) { + for (Iterator i = resource.listSameAs(); i.hasNext();) { OntResource subclass = (OntResource) i.next(); - for (Iterator j = subclass.listLabels(null); j.hasNext(); ) { + for (Iterator j = subclass.listLabels(null); j.hasNext();) { Literal l = (Literal) j.next(); subclasses.put(l.toString(), "1"); } } } } - return subclasses.keySet().iterator(); } /** - * retrieves synonyms from wordnet via sweet's web interface + * Retreives synonyms for an given phrase if the phrase + * is present in the ontology + * @param queryKeyPhrase an input string representing a phrase + * for which we wish to obtain synonyms. + * @return an {@link java.util.Iterator} containing synonyms string tokens + * or an empty if no synonyms exist for the given queryKeyPhrase. */ @Override public Iterator synonyms(String queryKeyPhrase) { - //need to have a html quote method instead - String qKeyPhrase = queryKeyPhrase.replaceAll("\\s+", "\\+"); - Map classMap = retrieve(qKeyPhrase); + Map classMap = retrieve(queryKeyPhrase); - Map synonyms = new HashMap<>(); + Map synonyms = new HashMap<>(); - Iterator iter = classMap.keySet().iterator(); + Iterator iter = classMap.keySet().iterator(); while (iter.hasNext()) { OntResource resource = (OntResource) iter.next(); //listLabels - for (Iterator i = resource.listLabels(null); i.hasNext(); ) { + for (Iterator i = resource.listLabels(null); i.hasNext();) { Literal l = (Literal) i.next(); synonyms.put(l.toString(), "1"); } if (resource instanceof Individual) { //get all individuals same as this one - for (Iterator i = resource.listSameAs(); i.hasNext(); ) { + for (Iterator i = resource.listSameAs(); i.hasNext();) { Individual individual = (Individual) i.next(); //add labels - for (Iterator j = individual.listLabels(null); j.hasNext(); ) { + for (Iterator j = individual.listLabels(null); j.hasNext();) { Literal l = (Literal) i.next(); synonyms.put(l.toString(), "1"); } } } else if (resource instanceof OntClass) { //list equivalent classes - for (Iterator i = ((OntClass) resource).listEquivalentClasses(); i.hasNext(); ) { + for (Iterator i = ((OntClass) resource).listEquivalentClasses(); i.hasNext();) { OntClass equivClass = (OntClass) i.next(); //add labels - for (Iterator j = equivClass.listLabels(null); j.hasNext(); ) { + for (Iterator j = equivClass.listLabels(null); j.hasNext();) { Literal l = (Literal) j.next(); synonyms.put(l.toString(), "1"); } @@ -231,7 +277,7 @@ public Iterator synonyms(String queryKeyPhrase) { return synonyms.keySet().iterator(); } - public static void addSearchTerm(String label, OntResource resource) { + public void addSearchTerm(String label, OntResource resource) { Map m = retrieve(label); if (m == null) { m = new HashMap<>(); @@ -240,21 +286,33 @@ public static void addSearchTerm(String label, OntResource resource) { searchTerms.put(label.toLowerCase(), m); } + /** + * A basic lookup function for retrieving keys (phrases or tokens) + * from the ontology search terms map. Right now only exact lookups + * will retrieve a result... this could be improved by using some + * advanced parsing logic... such as Lucene query parser. + * @param label the label (phrases or tokens) to retrieve from the + * ontology search terms map. + * @return an {@link java.util.Map} if there are match(es) + * or an empty {@link java.util.HashMap} if there are no + * matches. + */ public static Map retrieve(String label) { - @SuppressWarnings("unchecked") Map m = (Map) searchTerms.get(label.toLowerCase()); + @SuppressWarnings("unchecked") + Map m = (Map) searchTerms.get(label.toLowerCase()); if (m == null) { m = new HashMap<>(); } return m; } - protected static void renderHierarchy(PrintStream out, OntClass cls, List occurs, int depth) { + protected static void renderHierarchy(PrintStream out, OntClass cls, List occurs, int depth) { renderClassDescription(out, cls, depth); out.println(); // recurse to the next level down if (cls.canAs(OntClass.class) && !occurs.contains(cls)) { - for (Iterator i = cls.listSubClasses(true); i.hasNext(); ) { + for (Iterator i = cls.listSubClasses(true); i.hasNext(); ) { OntClass sub = (OntClass) i.next(); // we push this expression on the occurs list before we recurse @@ -262,11 +320,11 @@ protected static void renderHierarchy(PrintStream out, OntClass cls, List occurs renderHierarchy(out, sub, occurs, depth + 1); occurs.remove(cls); } - for (Iterator i = cls.listInstances(); i.hasNext(); ) { + for (Iterator i = cls.listInstances(); i.hasNext(); ) { Individual individual = (Individual) i.next(); renderURI(out, individual.getModel(), individual.getURI()); out.print(" ["); - for (Iterator j = individual.listLabels(null); j.hasNext(); ) { + for (Iterator j = individual.listLabels(null); j.hasNext(); ) { out.print(((Literal) j.next()).getString() + ", "); } out.print("] "); @@ -288,7 +346,7 @@ public static void renderClassDescription(PrintStream out, OntClass c, int depth out.print(c.getLocalName()); out.print(" ["); - for (Iterator i = c.listLabels(null); i.hasNext(); ) { + for (Iterator i = c.listLabels(null); i.hasNext(); ) { out.print(((Literal) i.next()).getString() + ", "); } out.print("] "); @@ -315,7 +373,7 @@ protected static void renderURI(PrintStream out, PrefixMapping prefixes, String } protected static void renderAnonymous(PrintStream out, Resource anon, String name) { - String anonID = (String) mAnonIDs.get(anon.getId()); + String anonID = mAnonIDs.get(anon.getId()); if (anonID == null) { anonID = "a-" + mAnonCount++; mAnonIDs.put(anon.getId(), anonID); @@ -333,92 +391,4 @@ protected static void indent(PrintStream out, int depth) { } } - public static void main(String[] args) throws Exception { - - // boolean options - Option helpOpt = new Option("h", "help", false, "show this help message"); - // argument options - Option ontDirOpt = OptionBuilder.hasArg(true).withArgName(ONT_DIR).withDescription("A directory containing .owl files.").isRequired(false).create(); - - // create the options - Options options = new Options(); - options.addOption(helpOpt); - options.addOption(ontDirOpt); - - String ontDir; - CommandLineParser parser = new GnuParser(); - try { - CommandLine line = parser.parse(options, args); - - if (line.hasOption(ONT_DIR)) { - ontDir = line.getOptionValue(ONT_DIR).replace("\\", "/"); - } else { - ontDir = LocalOntology.class.getClassLoader().getResource("ontology").getFile(); - } - if (!ontDir.endsWith("/")) { - ontDir += "/"; - } - } catch (Exception e) { - LOG.error("Error whilst processing main method of LocalOntology.", e); - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp("LocalOntology: 'ontDir' argument is mandatory. ", options, true); - return; - } - File fileDir = new File(ontDir); - //Fail if the input is not a directory. - if (fileDir.isDirectory()) { - List owlFiles = new ArrayList<>(); - for (File owlFile : fileDir.listFiles()) { - owlFiles.add(owlFile.toString()); - } - MudrodEngine mEngine = new MudrodEngine(); - Properties props = mEngine.loadConfig(); - Ontology ontology = new OntologyFactory(props).getOntology(); - //convert to correct iput for ontology loading. - String[] owlArray = new String[owlFiles.size()]; - owlArray = owlFiles.toArray(owlArray); - ontology.load(owlArray); - - String[] terms = new String[] { "Glacier ice" }; - //Demonstrate that we can do basic ontology heirarchy navigation and log output. - for (Iterator i = getParser().rootClasses(getModel()); i.hasNext(); ) { - - //print Ontology Class Hierarchy - OntClass c = i.next(); - renderHierarchy(System.out, c, new LinkedList<>(), 0); - - for (Iterator subClass = c.listSubClasses(true); subClass.hasNext(); ) { - OntClass sub = subClass.next(); - //This means that the search term is present as an OntClass - if (terms[0].equalsIgnoreCase(sub.getLabel(null))) { - //Add the search term(s) above to the term cache. - for (int j = 0; j < terms.length; j++) { - addSearchTerm(terms[j], sub); - } - - //Query the ontology and return subclasses of the search term(s) - for (int k = 0; k < terms.length; k++) { - Iterator iter = ontology.subclasses(terms[k]); - while (iter.hasNext()) { - LOG.info("Subclasses >> " + iter.next()); - } - } - - //print any synonymic relationships to demonstrate that we can - //undertake synonym-based query expansion - for (int l = 0; l < terms.length; l++) { - Iterator iter = ontology.synonyms(terms[l]); - while (iter.hasNext()) { - LOG.info("Synonym >> " + iter.next()); - } - } - } - } - } - - mEngine.end(); - } - - } - } diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyParser.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyParser.java index 9dce673..eca6252 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyParser.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyParser.java @@ -16,22 +16,24 @@ import org.apache.jena.ontology.OntClass; import org.apache.jena.ontology.OntModel; +import gov.nasa.jpl.mudrod.ontology.Ontology; + import java.util.Iterator; /** * Interface for specific ontology parsers e.g. .ttl, RDFXML, * etc. - * - * @author lewismc */ public interface OntologyParser { /** * An ontology model (RDF graph) to parse for literals. * + * @param ont the associated {@link gov.nasa.jpl.mudrod.ontology.Ontology} + * implementation processing the ontology operation(s). * @param ontModel the {@link org.apache.jena.ontology.OntModel} */ - public void parse(OntModel ontModel); + public void parse(Ontology ont, OntModel ontModel); /** * An ontology model (RDF graph) for which to obtain an diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java index 76ba5a9..42b894d 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java @@ -18,6 +18,10 @@ import org.apache.jena.ontology.OntModel; import org.apache.jena.rdf.model.Literal; +import com.esotericsoftware.minlog.Log; + +import gov.nasa.jpl.mudrod.ontology.Ontology; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -25,23 +29,26 @@ import java.util.regex.Pattern; /** - * implementation of parser for w3c's OWL files - * - * @author michael j pan + * {@link gov.nasa.jpl.mudrod.ontology.process.OntologyParser} + * implementation for W3C OWL + * files. */ public class OwlParser implements OntologyParser { + + private Ontology ont; public OwlParser() { //default constructor } /** - * parse owl ontology files using jena + * Parse OWL ontology files using Apache Jena */ @Override - public void parse(OntModel m) { - for (Iterator i = rootClasses(m); i.hasNext(); ) { - OntClass c = (OntClass) i.next(); + public void parse(Ontology ont, OntModel m) { + this.ont = ont; + for (Iterator i = rootClasses(m); i.hasNext(); ) { + OntClass c = i.next(); //dont deal with anonymous classes if (c.isAnon()) { @@ -52,7 +59,7 @@ public void parse(OntModel m) { } } - protected void parseClass(OntClass cls, List occurs, int depth) { + protected void parseClass(OntClass cls, List occurs, int depth) { //dont deal with anonymous classes if (cls.isAnon()) { return; @@ -60,7 +67,7 @@ protected void parseClass(OntClass cls, List occurs, int depth) { //add cls to Ontology searchterms //list labels - Iterator labelIter = cls.listLabels(null); + Iterator labelIter = cls.listLabels(null); //if has no labels if (!labelIter.hasNext()) { //add rdf:ID as a label @@ -71,13 +78,13 @@ protected void parseClass(OntClass cls, List occurs, int depth) { while (labelIter.hasNext()) { Literal l = (Literal) labelIter.next(); - // OntologyFactory.getOntology.addSearchTerm(l.toString(), cls); + ((LocalOntology) ont).addSearchTerm(l.toString(), cls); } // recurse to the next level down if (cls.canAs(OntClass.class) && !occurs.contains(cls)) { //list subclasses - for (Iterator i = cls.listSubClasses(true); i.hasNext(); ) { + for (Iterator i = cls.listSubClasses(true); i.hasNext(); ) { OntClass sub = (OntClass) i.next(); // we push this expression on the occurs list before we recurse @@ -87,23 +94,36 @@ protected void parseClass(OntClass cls, List occurs, int depth) { } //list instances - for (Iterator i = cls.listInstances(); i.hasNext(); ) { + for (Iterator i = cls.listInstances(); i.hasNext(); ) { //add search terms for each instance //list labels Individual individual = (Individual) i.next(); - for (Iterator j = individual.listLabels(null); j.hasNext(); ) { + for (Iterator j = individual.listLabels(null); j.hasNext(); ) { Literal l = (Literal) j.next(); - // OntologyImpl.addSearchTerm(l.toString(), individual); + ((LocalOntology) ont).addSearchTerm(l.toString(), individual); } } } } - public Iterator rootClasses(OntModel m) { - List roots = new ArrayList(); + /** + * Parses out all root classes of the given + * {@link org.apache.jena.ontology.OntModel} + * TODO This implementation DOES NOT currently handle + * aggregate/collection ontologies e.g. ontologies which have ONLY imports, + * and NO root classes such as + * sweetAll.owl. + * @param m the {@link org.apache.jena.ontology.OntModel} we wish to obtain + * all root classes for. + * @return an {@link java.util.Iterator} of {@link org.apache.jena.ontology.OntClass} + * elements representing all root classes. + */ + @Override + public Iterator rootClasses(OntModel m) { + List roots = new ArrayList<>(); - for (Iterator i = m.listClasses(); i.hasNext(); ) { + for (Iterator i = m.listClasses(); i.hasNext(); ) { OntClass c = (OntClass) i.next(); try { // too confusing to list all the restrictions as root classes @@ -115,12 +135,11 @@ public Iterator rootClasses(OntModel m) { // this class is directly descended from Thing roots.add(c); } else if (c.getCardinality(m.getProfile().SUB_CLASS_OF()) == 0) { - // this class has no super-classes - // (can occur if we're not using the reasoner) + // this class has no super-classes (can occur if we're not using the reasoner) roots.add(c); } } catch (Exception e) { - e.printStackTrace(); + Log.error("Error during extraction or root Classes from Ontology Model: ", e); } } diff --git a/core/src/main/resources/config.xml b/core/src/main/resources/config.xml index 1e910b6..62ac7a6 100644 --- a/core/src/main/resources/config.xml +++ b/core/src/main/resources/config.xml @@ -126,4 +126,4 @@ --> repartition - \ No newline at end of file + diff --git a/core/src/main/resources/ontology/ont.rdf b/core/src/main/resources/ontology/ont.rdf deleted file mode 100644 index ff8f84d..0000000 --- a/core/src/main/resources/ontology/ont.rdf +++ /dev/null @@ -1,1234 +0,0 @@ - - - - - - - - - - -]> - - - - - This ontology describes sensors and observations, and related concepts. It does not describe domain concepts, time, locations, etc. as these are intended to be included from other ontologies via OWL imports. - This ontology is based on the SSN Ontology by the W3C Semantic Sensor Networks Incubator Group (SSN-XG). - New modular version of the SSN ontology independent of DUL. - Semantic Sensor Network Ontology - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - for property - A relation between some aspect of a sensing entity and a property. For example, from a sensor to the properties it can observe, or from a deployment to the properties it was installed to observe. Also from a measurement capability to the property the capability is described for. (Used in conjunction with ofFeature). - - - - - - - - has measurement capability - Relation from a Sensor to a MeasurementCapability describing the measurement properties of the sensor. - - - - - - - - - has measurement property - Relation from a MeasurementCapability to a MeasurementProperty. For example, to an accuracy (see notes at MeasurementCapability). - - - - - - - - - in condition - Describes the prevailing environmental conditions for MeasurementCapabilites, OperatingConditions and SurvivalRanges. Used for example to say that a sensor has a particular accuracy in particular conditions. (see also MeasurementCapability) - - - - - - - - - - - - - - - - - - - - - - - - of feature - A relation between some aspect of a sensing entity and a feature. For example, from a sensor to the features it can observe properties of, or from a deployment to the features it was installed to observe. Also from a measurement capability to the feature the capability is described for. (Used in conjunction with forProperty). - - - - - - - - quality of observation - http://www.w3.org/2005/Incubator/ssn/wiki/SSN_Observation#Observation - skos:exactMatch 'resultQuality' [O&M - ISO/DIS 19156] - http://portal.opengeospatial.org/files/?artifact_id=41579 - Relation linking an Observation to the adjudged quality of the result. This is of course complimentary to the MeasurementCapability information recorded for the Sensor that made the Observation. - - - - - - - - - - detects - A relation from a sensor to the Stimulus that the sensor can detect. -The Stimulus itself will be serving as a proxy for (see isProxyOf) some observable property. - - - - - - - - - - - - - - - - - feature of interest - A relation between an observation and the entity whose quality was observed. For example, in an observation of the weight of a person, the feature of interest is the person and the quality is weight. - skos:exactMatch 'featureOfInterest' [O&M - ISO/DIS 19156] - http://portal.opengeospatial.org/files/?artifact_id=41579 - - - - - - - - - - - - - - has property - A relation between a FeatureOfInterest and a Property of that feature. - The chain here ensures that the observed property of an observation is a property of the feature of interest. This restriction is written in O&M; here we can enforce it formally. - -The more obvious formulation: - -featureOfInterest o hasProperty SubPropertyOf observedProperty - -can't be used, because (by the OWL2 decidability restrictions) that would mean cardinality restrictions couldn't be applied to observedProperty (see definition of Observation). - - - - - - - - - - - - - has value - - - - - - - - implemented by - A relation between the description of an algorithm, procedure or method and an entity that implements that method in some executable way. For example, between a scientific measuring method and a sensor the senses via that method. - - - - - - - - implements - A relation between an entity that implements a method in some executable way and the description of an algorithm, procedure or method. For example, between a Sensor and the scientific measuring method that the Sensor uses to observe a Property. - - - - - - - - - is produced by - Relation between a producer and a produced entity: for example, between a sensor and the produced output. - - - - - - - - is property of - Relation between a FeatureOfInterest and a Property (a Quality observable by a sensor) of that feature. - - - - - - - - isProxyFor - A relation from a Stimulus to the Property that the Stimulus is serving as a proxy for. For example, the expansion of the quicksilver is a stimulus that serves as a proxy for temperature, or an increase or decrease in the spinning of cups on a wind sensor is serving as a proxy for wind speed. - - - - - - - - - - - - - - - - made observation - Relation between a Sensor and Observations it has made. - - - - - - - - - observation result - Relation linking an Observation (i.e., a description of the context, the Situation, in which the observatioin was made) and a Result, which contains a value representing the value associated with the observed Property. - skos:closeMatch 'result' [O&M - ISO/DIS 19156] - http://portal.opengeospatial.org/files/?artifact_id=41579 - - - - - - - - observation result time - The result time is the time when the procedure associated with the observation act was applied. - The result time shall describe the time when the result became available, typically when the procedure associated with the observation was completed For some observations this is identical to the phenomenonTime. However, there are important cases where they differ.[O&M] - http://www.opengeospatial.org/standards/om - - - - - - - - observation sampling time - http://www.opengeospatial.org/standards/om - The sampling time is the time that the result applies to the feature-of-interest. This is the time usually required for geospatial analysis of the result. - Rebadged as phenomenon time in [O&M]. The phenomenon time shall describe the time that the result applies to the property of the feature-of-interest. This is often the time of interaction by a sampling procedure or observation procedure with a real-world feature. - - - - - - - - - - - - - - - observed property - skos:exactMatch 'observedProperty' [O&M - ISO/DIS 19156] - http://portal.opengeospatial.org/files/?artifact_id=41579 - Relation linking an Observation to the Property that was observed. The observedProperty should be a Property (hasProperty) of the FeatureOfInterest (linked by featureOfInterest) of this observation. - - - - - - - - The chain here means that if a sensor made an observation and that observation has a result, then the result is the one produced by the sensor. Just ensures that the sensor and the resulting observation agree on the result. - - - - - - - - - - - - - - sensing method used - http://www.bipm.org/en/committees/jc/jcgm/wg2.html - A (measurement) procedure is a detailed description of a measurement according to one or more measurement principles and to a given measurement method, based on a measurement model and including any calculation to obtain a measurement result [VIM 2.6] - - - - - - - has operating property - Relation from an OperatingRange to a Property. For example, to a battery lifetime. - - - - - - - - - has operating range - Relation from a System to an OperatingRange describing the normal operating environment of the System. - - - - - - - - - has survival property - Relation from a SurvivalRange to a Property describing the survial range of a system. For example, to the temperature extreme that a system can withstand before being considered damaged. - - - - - - - - - has survival range - A Relation from a System to a SurvivalRange. - - - - - - - - - - has subsystem - Haspart relation between a system and its parts. - - - - - - - - attached system - Relation between a Platform and any Systems (e.g., Sensors) that are attached to the Platform. - - - - - - - - deployed on platform - Relation between a deployment and the platform on which the system was deployed. - - - - - - - - - deployed system - Relation between a deployment and the deployed system. - - - - - - - - deployment process part - Has part relation between a deployment process and its constituent processes. - - - - - - - - has deployment - Relation between a System and a Deployment, recording that the System/Sensor was deployed in that Deployment. - - - - - - - - - in deployment - Relation between a Platform and a Deployment, recording that the object was used as a platform for a system/sensor for a particular deployment: as in this PhysicalObject is acting as a Platform inDeployment Deployment. - - - - - - - - on platform - Relation between a System (e.g., a Sensor) and a Platform. The relation locates the sensor relative to other described entities entities: i.e., the Sensor s1's location is Platform p1. More precise locations for sensors in space (relative to other entities, where attached to another entity, or in 3D space) are made using DOLCE's Regions (SpaceRegion). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Sensor - - - - - - - - - - - - - skos:exactMatch 'sensor' [SensorML OGC-0700] - http://www.opengeospatial.org/standards/sensorml - - skos:closeMatch 'observation procedure' [O&M] - http://www.opengeospatial.org/standards/om - -O&M allows sensors, methods, instruments, systems, algorithms and process chains as the processUsed of an observation; this ontology allows a similar range of things (any thing that can do sensing), just they are all grouped under the term sensor (which is thus wider than the O&M concept). - A sensor can do (implements) sensing: that is, a sensor is any entity that can follow a sensing method and thus observe some Property of a FeatureOfInterest. Sensors may be physical devices, computational methods, a laboratory setup with a person following a method, or any other thing that can follow a Sensing Method to observe a Property. - - - - - - - - - Accuracy - - The closeness of agreement between the value of an observation and the true value of the observed quality. - skos:exactMatch 'measurement accuracy/accuracy' [VIM 2.13] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - - - - - - - - Condition - - Used to specify ranges for qualities that act as conditions on a system/sensor's operation. For example, wind speed of 10-60m/s is expressed as a condition linking a quality, wind speed, a unit of measurement, metres per second, and a set of values, 10-60, and may be used as the condition on a MeasurementProperty, for example, to state that a sensor has a particular accuracy in that condition. - - - - - - - - detection limit - - skos:exactMatch 'detection limit' [VIM 4.18] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - An observed value for which the probability of falsely claiming the absence of a component in a material is β, given a probability α of falsely claiming its presence. - - - - - - - - Drift - - A, continuous or incremental, change in the reported values of observations over time for an unchanging quality. - skos:exactMatch 'instrumental drift' [VIM 4.21] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - - - - - - - - Measurement Capability - - - - - - - - - - - - - - - - - - - - Similar idea to MeasurementCapability in MMI Device Ontology - http://marinemetadata.org/community/teams/ontdevices - -But the the two express the relationship between constraints and multiple measurement properties differently. - -The conditions linked to a MeasurementCapability are skos:exactMatch to 'influence quantity' [VIM 2.52] -http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - Collects together measurement properties (accuracy, range, precision, etc) and the environmental conditions in which those properties hold, representing a specification of a sensor's capability in those conditions. - -The conditions specified here are those that affect the measurement properties, while those in OperatingRange represent the sensor's standard operating conditions, including conditions that don't affect the observations. - - - - - - - - MeasurementFrequency - - The smallest possible time between one observation and the next. - - - - - - - - MeasurementLatency - - The time between a request for an observation and the sensor producing a result (not including network latency to retrieve the result, just time from request to measurement.). - - - - - - - - Measurement Property - - An identifiable and observable characteristic of a sensor's observations or ability to make observations. - - - - - - - - Measurement Range - - skos:exactMatch 'measuring interval/measurement range' [VIM 4.7] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - The set of values that the sensor can return as the result of an observation under the defined conditions with the defined measurement properties. (If no conditions are specified or the conditions do not specify a range for the observed qualities, the measurement range is to be taken as the condition for the observed qualities.) - - - - - - - - Precision - - The closeness of agreement between replicate observations on an unchanged or similar quality value: i.e., a measure of a sensor's ability to consitently reproduce an observation. - skos:exactMatch 'measurement precision/precision' [VIM 2.15] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - - - - - - - - Resolution - - The smallest difference in the value of a quality being observed that would result in perceptably different values of observation results. - skos:exactMatch 'resolution' [VIM 4.14] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - - - - - - - - Response time - - skos:exactMatch 'step response time' [VIM 4.23] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - The time between a (step) change inthe value of an observed quality and a sensor (possibly with specified error) 'settling' on an observed value. - - - - - - - - Selectivity - - skos:exactMatch 'selectivity' [VIM 4.13] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - Selectivity is a property of a sensor whereby it provides observed values for one or more qualities such that the values of each quality are independent of other qualities in the phenomenon, body, or substance being investigated. - - - - - - - - Sensitivity - - skos:exactMatch 'sensitivity' [VIM 4.12] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - Sensitivity is the quotient of the change in a result of sensor and the corresponding change in a value of a quality being observed. - - - - - - - - - Feature of Interest - - - - - - - - - - - - - - A feature is an abstraction of real world phenomena (thing, person, event, etc). - skos:exactMatch 'feature' [O&M] - http://www.opengeospatial.org/standards/om - - - - - - - - Observation - - - - - - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 1 - - - - - - - 1 - - - - - - - - - skos:closeMatch 'observation' [O&M] - http://www.opengeospatial.org/standards/om - -Observation in this ontology and O&M are described differently (O&M records an observation as an act/event), but they record the same thing and are essentially interchangeable. The difference is in the ontological structure of the two, not the data or use. - -Observation here records a Situation (the estimation of the value of a Property) and a description of the method that was used (along with the participants), while O&M interprets an Observation as the event itself; there must, however, have been an event that lead to our situation, so both are records of events. The distinction is between the event itself and the record of what happened in that event. - - -skos:closeMatch 'measurement result' [VIM 2.9] http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - -Measurement result in VIM is the measured value plus any other relevant information, which means that measurement result and observation will often be associated to the same data (a value, a time, a property, etc.). - An Observation is a Situation in which a Sensing method has been used to estimate or calculate a value of a Property of a FeatureOfInterest. Links to Sensing and Sensor describe what made the Observation and how; links to Property and Feature detail what was sensed; the result is the output of a Sensor; other metadata details times etc. - - - - - - - - Observation Value - - - - - - - skos:exactMatch 'measured quantity value' [VIM 2.10] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - -skos:exactMatch 'observed value' [SensorML OGC-0700] -http://www.opengeospatial.org/standards/sensorml - -skos:closeMatch 'observation result' [O&M] -http://www.opengeospatial.org/standards/om - -O&M conflates what we have as SensorOutput and ObservationValue into observation result, though the OGC standard does say "result contains a value" and "a result which has a value", which fits naturally with the model here. - The value of the result of an Observation. An Observation has a result which is the output of some sensor, the result is an information object that encodes some value for a Feature. - - - - - - - - Property - - - - - - - An observable Quality of an Event or Object. That is, not a quality of an abstract entity as is also allowed by DUL's Quality, but rather an aspect of an entity that is intrinsic to and cannot exist without the entity and is observable by a sensor. - skos:exactMatch 'property' [O&M] - http://www.opengeospatial.org/standards/om - - - - - - - - Sensing - http://www.w3.org/2005/Incubator/sso/ - The description of a process (i.e. describes the temporal and dataflow dependencies and relationships amongst its parts) that results in the estimation, or calculation, of the value of a phenomenon. - - - - - - - - Sensor Output - - - - - - - - - - - - - A sensor outputs a piece of information (an observed value), the value itself being represented by an ObservationValue. - http://www.w3.org/2005/Incubator/ssn/ - - skos:closeMatch 'observation result' [O&M] - http://www.opengeospatial.org/standards/om - -See comments at ObservationValue. - - - - - - - - Stimulus - - - - - - - An Event in the real world that 'triggers' the sensor. The properties associated to the stimulus may be different to eventual observed property. It is the event, not the object that triggers the sensor. - http://www.w3.org/2005/Incubator/sso/ - - - - - - - Battery Lifetime - - Total useful life of a battery. - - - - - - - - Device - - A device is a physical piece of technology - a system in a box. Devices may of course be built of smaller devices and software components (i.e. systems have components). - - - - - - - - Maintenance Schedule - - Schedule of maintenance for a system/sensor in the specified conditions. - - - - - - - - Operating Power Range - - Power range in which system/sensor is expected to operate. - - - - - - - - Operating Property - - An identifiable characteristic of the environmental and other conditions in which the sensor is intended to operate. May include power ranges, power sources, standard configurations, attachments and the like. - - - - - - - - Operating Range - - - - - - - - - - - - - - skos:broaderMatch 'reference operating condition' [VIM 4.11] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - -The difference is that here we also allow for qualities that aren't VIM influence quantities [VIM 2.52] - for example, a quantity that alters the power requirements, but doesn't affect the measurement properties - conditions specified in MeasurementCapability should be influence quantities. - The environmental conditions and characteristics of a system/sensor's normal operating environment. Can be used to specify for example the standard environmental conditions in which the sensor is expected to operate (a Condition with no OperatingProperty), or how the environmental and other operating properties relate: i.e., that the maintenance schedule or power requirements differ according to the conditions. - - - - - - - - Sensing Device - - - A sensing device is a device that implements sensing. - - - - - - - - Sensor Data Sheet - A data sheet records properties of a sensor. A data sheet might describe for example the accuracy in various conditions, the power use, the types of connectors that the sensor has, etc. - -Generally a sensor's properties are recorded directly (with hasMeasurementCapability, for example), but the data sheet can be used for example to record the manufacturers specifications verses observed capabilites, or if more is known than the manufacturer specifies, etc. The data sheet is an information object about the sensor's properties, rather than a direct link to the actual properties themselves. - - - - - - - - Survival Property - - An identifiable characteristic that represents the extent of the sensors useful life. Might include for example total battery life or number of recharges, or, for sensors that are used only a fixed number of times, the number of observations that can be made before the sensing capability is depleted. - - - - - - - - Survival Range - - - - - - - - - - - - - - skos:narrowerMatch 'limiting operating condition' [VIM 4.10] - http://www.bipm.org/utils/common/documents/jcgm/JCGM_200_2008.pdf - The conditions a sensor can be exposed to without damage: i.e., the sensor continues to operate as defined using MeasurementCapability. If, however, the SurvivalRange is exceeded, the sensor is 'damaged' and MeasurementCapability specifications may no longer hold. - - - - - - - - System - - - - - - - - - - - - - - - - - - - - - - - - - System is a unit of abstraction for pieces of infrastructure (and we largely care that they are) for sensing. A system has components, its subsystems, which are other systems. - - - - - - - - - - - - - - - - - - - - - System Lifetime - - Total useful life of a sensor/system (expressed as total life since manufacture, time in use, number of operations, etc.). - - - - - - Deployment - - - - - - - - - - - - - - skos:closeMatch 'Deployment' [MMI Dev] - http://marinemetadata.org/community/teams/ontdevices - The ongoing Process of Entities (for the purposes of this ontology, mainly sensors) deployed for a particular purpose. For example, a particular Sensor deployed on a Platform, or a whole network of Sensors deployed for an observation campaign. The deployment may have sub processes, such as installation, maintenance, addition, and decomissioning and removal. - - - - - - - - Deployment-related Process - - - - - - - Place to group all the various Processes related to Deployment. For example, as well as Deplyment, installation, maintenance, deployment of further sensors and the like would all be classified under DeploymentRelatedProcess. - - - - - - - - Platform - - - - - - - - - - - - - An Entity to which other Entities can be attached - particuarly Sensors and other Platforms. For example, a post might act as the Platform, a bouy might act as a Platform, or a fish might act as a Platform for an attached sensor. - skos:exactMatch 'platform' [SensorML OGC-0700] - http://www.opengeospatial.org/standards/sensorml - - - - - - - - - - diff --git a/core/src/test/java/gov/nasa/jpl/mudrod/ontology/process/TestLocalOntology.java b/core/src/test/java/gov/nasa/jpl/mudrod/ontology/process/TestLocalOntology.java new file mode 100644 index 0000000..994f4ed --- /dev/null +++ b/core/src/test/java/gov/nasa/jpl/mudrod/ontology/process/TestLocalOntology.java @@ -0,0 +1,226 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); you + * may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package gov.nasa.jpl.mudrod.ontology.process; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Test cases for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology} + */ +public class TestLocalOntology { + + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + /** + * @throws java.lang.Exception + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + private LocalOntology lOnt; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + lOnt = new LocalOntology(); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + lOnt = null; + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#LocalOntology()}. + */ + @Test + public final void testLocalOntology() { + assertNotNull("Test setUp should create a new instance of LocalOntology.", lOnt); + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#getInstance()}. + */ + @Test + public final void testGetInstance() { + assertSame("Ontology instance should be of type LocalOntology", LocalOntology.class, lOnt.getInstance().getClass()); + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#load()}. + * @throws IOException + */ + @Ignore + @Test + public final void testLoad() throws IOException { + lOnt.load(); + assertTrue("Resource list should have a minimum of one resource.", lOnt.getLoadedOntologyResources().size() == 1); + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#load(java.lang.String[])}. + */ + @Ignore + @Test + public final void testLoadStringArray() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#getParser()}. + */ + @Ignore + @Test + public final void testGetParser() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#getModel()}. + */ + @Ignore + @Test + public final void testGetModel() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#merge(gov.nasa.jpl.mudrod.ontology.Ontology)}. + */ + @Ignore + @Test + public final void testMerge() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#subclasses(java.lang.String)}. + */ + @Ignore + @Test + public final void testSubclasses() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#synonyms(java.lang.String)}. + */ + @Ignore + @Test + public final void testSynonyms() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#addSearchTerm(java.lang.String, org.apache.jena.ontology.OntResource)}. + */ + @Ignore + @Test + public final void testAddSearchTerm() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#retrieve(java.lang.String)}. + */ + @Ignore + @Test + public final void testRetrieve() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderHierarchy(java.io.PrintStream, org.apache.jena.ontology.OntClass, java.util.List, int)}. + */ + @Ignore + @Test + public final void testRenderHierarchy() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderClassDescription(java.io.PrintStream, org.apache.jena.ontology.OntClass, int)}. + */ + @Ignore + @Test + public final void testRenderClassDescription() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderRestriction(java.io.PrintStream, org.apache.jena.ontology.Restriction)}. + */ + @Ignore + @Test + public final void testRenderRestriction() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderURI(java.io.PrintStream, org.apache.jena.shared.PrefixMapping, java.lang.String)}. + */ + @Ignore + @Test + public final void testRenderURI() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderAnonymous(java.io.PrintStream, org.apache.jena.rdf.model.Resource, java.lang.String)}. + */ + @Ignore + @Test + public final void testRenderAnonymous() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#indent(java.io.PrintStream, int)}. + */ + @Ignore + @Test + public final void testIndent() { + fail("Not yet implemented"); // TODO + } + + /** + * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#main(java.lang.String[])}. + */ + @Ignore + @Test + public final void testMain() { + fail("Not yet implemented"); // TODO + } + +} diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/OntologyResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/OntologyResource.java index b0d44ff..e0ade84 100644 --- a/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/OntologyResource.java +++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/OntologyResource.java @@ -19,10 +19,15 @@ import org.slf4j.LoggerFactory; import javax.servlet.ServletContext; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -51,10 +56,10 @@ public Response status() { @Path("/synonym") @Produces(MediaType.APPLICATION_JSON) @Consumes("text/plain") - public Response getOntologySynonyms(@QueryParam("query") String term) { + public Response getOntologySynonyms(@QueryParam("query") String query) { List result = new ArrayList<>(); - if (term != null) { - Iterator synonyms = ontImpl.synonyms(term); + if (query != null) { + Iterator synonyms = ontImpl.synonyms(query); while (synonyms.hasNext()) { result.add((String) synonyms.next()); } @@ -68,10 +73,10 @@ public Response getOntologySynonyms(@QueryParam("query") String term) { @Path("/subclass") @Produces(MediaType.APPLICATION_JSON) @Consumes("text/plain") - public Response getOntologySubclasses(@QueryParam("query") String term) { + public Response getOntologySubclasses(@QueryParam("query") String query) { List result = new ArrayList<>(); - if (term != null) { - Iterator subclasses = ontImpl.subclasses(term); + if (query != null) { + Iterator subclasses = ontImpl.subclasses(query); while (subclasses.hasNext()) { result.add((String) subclasses.next()); } diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchDatasetDetailResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchDatasetDetailResource.java index d1be0a4..ce20569 100644 --- a/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchDatasetDetailResource.java +++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchDatasetDetailResource.java @@ -57,16 +57,14 @@ public Response status() { @Produces(MediaType.APPLICATION_JSON) @Consumes("text/plain") public Response searchDatasetDetail(@QueryParam("shortname") String shortName) { - Properties config = mEngine.getConfig(); String dataDetailJson = null; try { String query = "Dataset-ShortName:\"" + shortName + "\""; dataDetailJson = mEngine.getESDriver().searchByQuery(config.getProperty(MudrodConstants.ES_INDEX_NAME), config.getProperty(MudrodConstants.RAW_METADATA_TYPE), query, true); } catch (InterruptedException | ExecutionException | IOException e) { - LOG.error("Error whilst searching for a Dataset-ShortName", e); + LOG.error("Error whilst searching for a Dataset-ShortName: ", e); } - LOG.info("Response received: {}", dataDetailJson); return Response.ok(dataDetailJson, MediaType.APPLICATION_JSON).build(); } From 2893e13e311099e19e4587476b1783a06d93cd60 Mon Sep 17 00:00:00 2001 From: fgreg Date: Tue, 30 May 2017 09:29:12 -0700 Subject: [PATCH 03/33] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a627cd1..15129b7 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,8 @@ The REST API documentation can also be seen at [https://mudrod.github.io/miredot * David Moroni - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov) * Chris Finch - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov) * [Lewis John Mcgibbney](https://www.linkedin.com/in/lmcgibbney) - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov) - + * [Frank Greguska](https://www.linkedin.com/in/frankgreguska/) - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov) + # License This source code is licensed under the [Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0), a copy of which is shipped with this project. From 40ab62ed028685756a0faaadc8160a7a995799d4 Mon Sep 17 00:00:00 2001 From: Lewis John McGibbney Date: Tue, 30 May 2017 22:54:39 -0700 Subject: [PATCH 04/33] ISSUE-186 Implement parsing of root classes for aggregate/collection ontologies (#187) ISSUE-186 Implement parsing of root classes for aggregate/collection ontologies --- .../ontology/process/LocalOntology.java | 12 +++---- .../mudrod/ontology/process/OwlParser.java | 31 +++++++++++++------ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java index 98de33a..55ca51d 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java @@ -14,6 +14,7 @@ package gov.nasa.jpl.mudrod.ontology.process; import gov.nasa.jpl.mudrod.ontology.Ontology; + import org.apache.jena.ontology.Individual; import org.apache.jena.ontology.OntClass; import org.apache.jena.ontology.OntModel; @@ -50,7 +51,7 @@ public class LocalOntology implements Ontology { public static final String DELIMITER_SEARCHTERM = " "; - private static Map searchTerms = new HashMap<>(); + private Map searchTerms = new HashMap<>(); private static OntologyParser parser; private static OntModel ontologyModel; private Ontology ontology; @@ -95,11 +96,8 @@ public Ontology getInstance() { public void load() { URL ontURL = null; try { - //TODO aggregate/collection ontologies e.g. ontologies which have ONLY imports, - //such as sweetAll.owl are not currently supported. See Javadoc comment in - // gov.nasa.jpl.mudrod.ontology.process.OwlParser#rootClasses - //ontURL = new URL("https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl"); - ontURL = new URL("https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/reprDataProduct.owl"); + ontURL = new URL("https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl"); + //ontURL = new URL("https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/reprDataProduct.owl"); } catch (MalformedURLException e) { LOG.error("Error when attempting to create URL resource: ", e); } @@ -297,7 +295,7 @@ public void addSearchTerm(String label, OntResource resource) { * or an empty {@link java.util.HashMap} if there are no * matches. */ - public static Map retrieve(String label) { + public Map retrieve(String label) { @SuppressWarnings("unchecked") Map m = (Map) searchTerms.get(label.toLowerCase()); if (m == null) { diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java index 42b894d..e43f04d 100644 --- a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java +++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -36,6 +37,7 @@ public class OwlParser implements OntologyParser { private Ontology ont; + private List roots = new ArrayList<>(); public OwlParser() { //default constructor @@ -110,10 +112,6 @@ protected void parseClass(OntClass cls, List occurs, int depth) { /** * Parses out all root classes of the given * {@link org.apache.jena.ontology.OntModel} - * TODO This implementation DOES NOT currently handle - * aggregate/collection ontologies e.g. ontologies which have ONLY imports, - * and NO root classes such as - * sweetAll.owl. * @param m the {@link org.apache.jena.ontology.OntModel} we wish to obtain * all root classes for. * @return an {@link java.util.Iterator} of {@link org.apache.jena.ontology.OntClass} @@ -121,8 +119,19 @@ protected void parseClass(OntClass cls, List occurs, int depth) { */ @Override public Iterator rootClasses(OntModel m) { - List roots = new ArrayList<>(); + Iterator i = m.listClasses(); + if (i.hasNext() && i.next() instanceof OntClass) { + //assume ontology has root classes + processSingle(m); + } else { + //check for presence of aggregate/collection ontologies such as sweetAll.owl + processCollection(m); + } + + return roots.iterator(); + } + private void processSingle(OntModel m) { for (Iterator i = m.listClasses(); i.hasNext(); ) { OntClass c = (OntClass) i.next(); try { @@ -131,19 +140,21 @@ public Iterator rootClasses(OntModel m) { continue; } - if (c.hasSuperClass(m.getProfile().THING(), true)) { + if (c.hasSuperClass(m.getProfile().THING(), true) || c.getCardinality(m.getProfile().SUB_CLASS_OF()) == 0) { // this class is directly descended from Thing roots.add(c); - } else if (c.getCardinality(m.getProfile().SUB_CLASS_OF()) == 0) { - // this class has no super-classes (can occur if we're not using the reasoner) - roots.add(c); } } catch (Exception e) { Log.error("Error during extraction or root Classes from Ontology Model: ", e); } } + } - return roots.iterator(); + private void processCollection(OntModel m) { + for (Iterator i = m.listSubModels(true); i.hasNext(); ) { + OntModel ontModel = (OntModel) i.next(); + processSingle(ontModel); + } } public String rdfidToLabel(String idString) { From 1993aa636734c1161a37ace7bfc26b80c6953541 Mon Sep 17 00:00:00 2001 From: Frank Greguska Date: Mon, 12 Jun 2017 10:07:09 -0700 Subject: [PATCH 05/33] code cleanup ; --- web/META-INF/resources/js/controllers.js | 246 +++++++++++------------ 1 file changed, 114 insertions(+), 132 deletions(-) diff --git a/web/META-INF/resources/js/controllers.js b/web/META-INF/resources/js/controllers.js index 5c4d64e..8e04fb7 100755 --- a/web/META-INF/resources/js/controllers.js +++ b/web/META-INF/resources/js/controllers.js @@ -17,76 +17,62 @@ /* Controllers */ var mudrodControllers = angular.module('mudrodControllers', []); -mudrodControllers.controller('searchCtrl', ['$scope', '$rootScope', '$location', 'Autocomplete', 'SearchOptions', +mudrodControllers.controller('searchCtrl', ['$scope', '$rootScope', '$location', 'Autocomplete', 'SearchOptions', function ($scope, $rootScope, $location, Autocomplete, SearchOptions) { $scope.options = { opt: 'Or' }; - //if ($rootScope.SearchOptions.opt != null) - // $scope.options.opt = $rootScope.searchOptions.opt; - - //$scope.relatedTerms = []; - //$rootScope.searchOptions = {}; - - $scope.complete = function(string) { - $scope.hidethis = false; - $scope.hideoption = true; - var output = []; + $scope.complete = function (string) { + $scope.hidethis = false; Autocomplete.get({term: string}, function success(response) { - //alert($scope.challenge.question); - //console.log("Success:" + JSON.stringify(response)); - //$scope.blogList = response; $scope.filterSearch = response; }, function error(errorResponse) { console.log("Error:" + JSON.stringify(errorResponse)); } - ); - } + ); + }; - $scope.fillTextbox = function(string){ - $scope.options.query = string; - $scope.hidethis = true; - $scope.hideoption = false; + $scope.fillTextbox = function (string) { + $scope.options.query = string; + $scope.hidethis = true; document.getElementById("search-btn").focus(); - } + }; - $scope.search = function(options) { + $scope.search = function (options) { $rootScope.searchOptions = angular.copy(options); $location.path("/metadataView/" + options.query + '/' + options.opt); }; - $scope.$watch(function () { return SearchOptions.getSearchOptions(); }, function (newValue, oldValue) { - if (newValue != null) { - $scope.options.query= newValue.query; - $scope.options.opt= newValue.opt; + $scope.$watch(function () { + return SearchOptions.getSearchOptions(); + }, function (newValue, oldValue) { + if (newValue !== null) { + $scope.options.query = newValue.query; + $scope.options.opt = newValue.opt; } }, true); }]); - + mudrodControllers.controller('vocabularyCtrl', ['$scope', '$rootScope', 'VocabList', function vocabularyCtrl($scope, $rootScope, VocabList) { var word = $rootScope.searchOptions.query; - var opt = $rootScope.searchOptions.opt; VocabList.get({query: word}, - function success(response) { - //alert($scope.challenge.question); - //console.log("Success:" + JSON.stringify(response)); - //$scope.blogList = response; - $scope.ontologyList = response.graph.ontology; + function success(response) { + $scope.ontologyList = response.graph.ontology; - }, - function error(errorResponse) { - console.log("Error:" + JSON.stringify(errorResponse)); - } + }, + function error(errorResponse) { + console.log("Error:" + JSON.stringify(errorResponse)); + } ); }]); -mudrodControllers.controller('metadataViewCtrl', ['$rootScope', '$scope', '$routeParams', 'MetaData', 'PagerService', 'SearchOptions', +mudrodControllers.controller('metadataViewCtrl', ['$rootScope', '$scope', '$routeParams', 'MetaData', 'PagerService', 'SearchOptions', function metadataViewCtrl($rootScope, $scope, $routeParams, MetaData, PagerService, SearchOptions) { var vm = this; vm.PDItems = []; @@ -94,57 +80,57 @@ mudrodControllers.controller('metadataViewCtrl', ['$rootScope', '$scope', '$rout vm.setPage = setPage; vm.rankData = rankData; vm.totalMatches = 0; - - var word = new String(); - var opt = new String(); + + var word = String(); + var opt = String(); var rankopt = 'Rank-SVM'; - - if(!$routeParams.query){ - word = $rootScope.searchOptions.query; - opt = $rootScope.searchOptions.opt; - SearchOptions.setSearchOptions({'query':word, 'opt':opt}); + + if (!$routeParams.query) { + word = $rootScope.searchOptions.query; + opt = $rootScope.searchOptions.opt; + SearchOptions.setSearchOptions({'query': word, 'opt': opt}); } else { word = $routeParams.query; opt = $routeParams.opt; - - var searchKeyWords = new String(); - if (word.search(',') != -1) { - var topics = word.split(','); + var searchKeyWords = String(); + var topics; + + if (word.search(',') !== -1) { + topics = word.split(','); for (var i = 0; i < topics.length; i++) { searchKeyWords += topics[i]; } } else { searchKeyWords = word; } - - if (searchKeyWords.search('/') != -1 ) { - var topics = searchKeyWords.split('/'); + + if (searchKeyWords.search('/') !== -1) { + topics = searchKeyWords.split('/'); searchKeyWords = ""; for (var i = 0; i < topics.length; i++) { searchKeyWords += topics[i]; } - } - + } + word = searchKeyWords; - if(!$rootScope.searchOptions) { + if (!$rootScope.searchOptions) { $rootScope.searchOptions = {}; opt = 'Or'; } - else + else { opt = $rootScope.searchOptions.opt; + } - SearchOptions.setSearchOptions({'query':word, 'opt':opt}); + SearchOptions.setSearchOptions({'query': word, 'opt': opt}); $rootScope.searchOptions.query = searchKeyWords; $rootScope.searchOptions.opt = opt; searchMetadata(); - //opt = 'And'; } function initController() { - // initialize to page 1 vm.setPage(1); } @@ -159,120 +145,116 @@ mudrodControllers.controller('metadataViewCtrl', ['$rootScope', '$scope', '$rout // get current page of items vm.items = vm.PDItems.slice(vm.pager.startIndex, vm.pager.endIndex + 1); } - - function rankData(opt){ - rankopt = opt; - searchMetadata(); + + function rankData(opt) { + rankopt = opt; + searchMetadata(); } - this.searchTopic = function(topic) { - var searchKeyWords = new String(); + this.searchTopic = function (topic) { + var searchKeyWords = String(); + var topics; - if (topic.search(',') != -1 ) { - var topics = topic.split(','); + if (topic.search(',') !== -1) { + topics = topic.split(','); for (var i = 0; i < topics.length; i++) { searchKeyWords += topics[i]; } } else { searchKeyWords = topic; - } - - if (searchKeyWords.search('/') != -1) { - var topics = searchKeyWords.split('/'); + } + + if (searchKeyWords.search('/') !== -1) { + topics = searchKeyWords.split('/'); searchKeyWords = ""; for (var i = 0; i < topics.length; i++) { searchKeyWords += topics[i]; } - } - + } + $rootScope.searchOptions.query = searchKeyWords; - MetaData.get({query: searchKeyWords, operator: opt}, + MetaData.get({query: searchKeyWords, operator: opt}, function success(response) { vm.PDItems = response.PDResults; vm.totalMatches = vm.PDItems.length; vm.query = word; vm.opt = opt; initController(); - //$scope.PDResults = response.PDResults; - }, function error(errorResponse) { console.log("Error:" + JSON.stringify(errorResponse)); } ); - } - - function searchMetadata(){ - MetaData.get({query: word, operator: opt, rankoption: rankopt}, - function success(response) { - vm.PDItems = response.PDResults; - vm.totalMatches = vm.PDItems.length; - vm.query = word; - vm.opt = opt; - initController(); - //$scope.PDResults = response.PDResults; - }, - function error(errorResponse) { - console.log("Error:" + JSON.stringify(errorResponse)); - } + }; + + function searchMetadata() { + MetaData.get({query: word, operator: opt, rankoption: rankopt}, + function success(response) { + vm.PDItems = response.PDResults; + vm.totalMatches = vm.PDItems.length; + vm.query = word; + vm.opt = opt; + initController(); + }, + function error(errorResponse) { + console.log("Error:" + JSON.stringify(errorResponse)); + } ); } }]); mudrodControllers.controller('datasetViewCtrl', ['$rootScope', '$scope', '$routeParams', 'DatasetDetail', 'SearchOptions', function datasetViewCtrl($rootScope, $scope, $routeParams, DatasetDetail, SearchOptions) { - var shortname = $routeParams.shortname; - - var query = new String(); - var opt = new String(); - if(!$routeParams.query){ - query = $rootScope.searchOptions.query; - opt = $rootScope.searchOptions.opt; - SearchOptions.setSearchOptions({'query':query, 'opt':opt}); + var shortname = $routeParams.shortname; + + var query = String(); + var opt = String(); + if (!$routeParams.query) { + query = $rootScope.searchOptions.query; + opt = $rootScope.searchOptions.opt; + SearchOptions.setSearchOptions({'query': query, 'opt': opt}); } else { - query = $routeParams.query; + query = $routeParams.query; opt = $routeParams.opt; $rootScope.searchOptions.query = query; $rootScope.searchOptions.opt = opt; - SearchOptions.setSearchOptions({'query':query, 'opt':opt}); + SearchOptions.setSearchOptions({'query': query, 'opt': opt}); } - - DatasetDetail.get({shortname: shortname}, - function success(response) { - var dataAccessUrls; - - $scope.dataset = response.PDResults[0]; - var dataAccessUrl = $scope.dataset['DatasetLocationPolicy-BasePath']; - if(dataAccessUrl.search(',') != -1) { - dataAccessUrls = dataAccessUrl.split(','); - $scope.ftpUrl = dataAccessUrls[0]; - $scope.httpsUrl = dataAccessUrls[1]; - $scope.hideUrls = false; - $scope.hideUrl = true; - } else { - $scope.hideUrl = false; - $scope.hideUrls = true; - } - }, - function error(errorResponse) { - console.log("Error:" + JSON.stringify(errorResponse)); + + DatasetDetail.get({shortname: shortname}, + function success(response) { + var dataAccessUrls; + + $scope.dataset = response.PDResults[0]; + var dataAccessUrl = $scope.dataset['DatasetLocationPolicy-BasePath']; + if (dataAccessUrl.search(',') !== -1) { + dataAccessUrls = dataAccessUrl.split(','); + $scope.ftpUrl = dataAccessUrls[0]; + $scope.httpsUrl = dataAccessUrls[1]; + $scope.hideUrls = false; + $scope.hideUrl = true; + } else { + $scope.hideUrl = false; + $scope.hideUrls = true; } + }, + function error(errorResponse) { + console.log("Error:" + JSON.stringify(errorResponse)); + } ); }]); mudrodControllers.controller('hRecommendationCtrl', ['$scope', '$routeParams', 'HRecommendation', function hRecommendationCtrl($scope, $routeParams, HRecommendation) { - var shortname = $routeParams.shortname; - HRecommendation.get({shortname: shortname}, - function success(response) { - //alert($scope.challenge.question); - // console.log("Success:" + JSON.stringify(response)); - $scope.recommendationList = response.HybridRecommendationData.linked; + var shortname = $routeParams.shortname; + HRecommendation.get({shortname: shortname}, + function success(response) { + $scope.recommendationList = response.HybridRecommendationData.linked; - }, - function error(errorResponse) { - console.log("Error:" + JSON.stringify(errorResponse)); - } + }, + function error(errorResponse) { + console.log("Error:" + JSON.stringify(errorResponse)); + } ); }]); From 46756c5edc838cb8fd4bf3f0cc153f6d8977b4d3 Mon Sep 17 00:00:00 2001 From: Frank Greguska Date: Mon, 12 Jun 2017 10:10:53 -0700 Subject: [PATCH 06/33] css cleanup --- web/META-INF/resources/css/index.css | 462 ++++++++++++++++----------- 1 file changed, 270 insertions(+), 192 deletions(-) diff --git a/web/META-INF/resources/css/index.css b/web/META-INF/resources/css/index.css index 109d35b..aff33d8 100644 --- a/web/META-INF/resources/css/index.css +++ b/web/META-INF/resources/css/index.css @@ -83,11 +83,12 @@ a:link, a:visited { .view-area { background-image: url('../images/OceanWave.jpg'); - background-repeat:repeat-y; - background-size:cover; + background-repeat: repeat-y; + background-size: cover; line-height: 1.42857143; width: 100%; } + .landing-dialog { flex: 1; padding: 80px; @@ -110,16 +111,6 @@ a:link, a:visited { text-shadow: 1px 1px 1px #111; } -.fa { - display: inline-block; - font-family: FontAwesome; - font-style: normal; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - .searchBox { height: 100px; padding: .5em 0; @@ -297,13 +288,13 @@ a { transition: 0.3s; } -.sidenav a:hover, .offcanvas a:focus{ +.sidenav a:hover, .offcanvas a:focus { color: #f1f1f1; } .no-gutter > [class*='col-'] { - padding-right:5px; - padding-left:5px; + padding-right: 5px; + padding-left: 5px; } .content-holder .post-holder { @@ -318,7 +309,7 @@ a { .post-holder .post { background-color: #FFFFFF; - border-bottom: 1px solid #c3c3c3; + border-bottom: 1px solid #c3c3c3; padding: 14px 16px; } @@ -403,21 +394,21 @@ a { padding-right: 35px; width: 100%; background: #f3f3f3; - box-shadow: none!important; + box-shadow: none !important; } .searchOption { color: white; } -li{ +li { color: black; - cursor:pointer; -} -li:hover -{ - background-color:#f9f9f9; -} + cursor: pointer; +} + +li:hover { + background-color: #f9f9f9; +} .serch-ul { position: absolute; @@ -428,7 +419,7 @@ li:hover list-style: none; padding: 5px 0; margin: 2px 0 0; - box-shadow: 0 6px 12px rgba(0,0,0,.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); } /* @@ -438,14 +429,14 @@ li:hover */ /* --- GLOBAL FOOTER STYLES --- */ #site_footer { - position: relative; - width: 100%; - bottom: 0; - padding: 1em 2em 1em 2em; - margin: 0 auto; - background-color: black; -} - + position: relative; + width: 100%; + bottom: 0; + padding: 1em 2em 1em 2em; + margin: 0 auto; + background-color: black; +} + #site_footer .gradient_line { margin-left: auto; margin-right: auto; @@ -457,258 +448,345 @@ li:hover background: -moz-linear-gradient(left, transparent, #61b6fd, transparent); background: -webkit-linear-gradient(left, transparent, #61b6fd, transparent); background: linear-gradient(to right, rgba(0, 0, 0, 0), #61b6fd, rgba(0, 0, 0, 0)); - width: 90%; } - @media (min-width: 769px) { - #site_footer .gradient_line { - width: 50%; + width: 90%; +} + +@media (min-width: 769px) { + #site_footer .gradient_line { + width: 50%; } - } +} /* --- end GLOBAL FOOTER STYLES --- */ /* --- UPPER FOOTER --- */ - + .upper_footer .share, .upper_footer .footer_newsletter { text-align: center; padding: 1.69492%; /* margin-bottom: 3em; */ - width: 100%; + width: 100%; } - + .upper_footer .share h2, .upper_footer .footer_newsletter h2 { - font-size: 2em; - font-weight: 600; - margin-bottom: 0.6em; - color: white; - letter-spacing: -.035em; + font-size: 2em; + font-weight: 600; + margin-bottom: 0.6em; + color: white; + letter-spacing: -.035em; } - + @media (min-width: 600px) { .upper_footer .footer_newsletter { - width: 48.71795%; - float: left; - margin-left: 0; - margin-right: -100%; } + width: 48.71795%; + float: left; + margin-left: 0; + margin-right: -100%; + } } - + @media (min-width: 769px) { .upper_footer .footer_newsletter { - width: 40.67797%; - float: left; - margin-left: 8.47458%; - margin-right: -100%; } + width: 40.67797%; + float: left; + margin-left: 8.47458%; + margin-right: -100%; + } } - + @media (min-width: 600px) { .upper_footer .share { - width: 48.71795%; - float: left; - margin-left: 51.28205%; - margin-right: -100%; } + width: 48.71795%; + float: left; + margin-left: 51.28205%; + margin-right: -100%; + } } - + @media (min-width: 769px) { .upper_footer .share { - width: 40.67797%; - float: left; - margin-left: 50.84746%; - margin-right: -100%; } + width: 40.67797%; + float: left; + margin-left: 50.84746%; + margin-right: -100%; + } } /* --- end UPPER FOOTER --- */ /* --- SITE MAP (middle footer area) --- */ #site_footer .sitemap { - margin-bottom: 3em; } - @media (min-width: 600px) { + margin-bottom: 3em; +} + +@media (min-width: 600px) { #site_footer .sitemap .grid_layout { - width: 100%; } } - @media (min-width: large) { + width: 100%; + } +} + +@media (min-width: 64.063em) { #site_footer .sitemap .grid_layout { - width: 97%; } } + width: 97%; + } +} + #site_footer .sitemap_directory { - overflow: hidden; - *zoom: 1; - margin-bottom: 3em; } - #site_footer .sitemap_directory .footer_sitemap_item { - margin-bottom: .6em; } - @media (min-width: 600px) { - #site_footer .sitemap_directory .footer_sitemap_item { - margin-bottom: .2em; } } - @media (min-width: 1024px) { - #site_footer .sitemap_directory .footer_sitemap_item { + overflow: hidden; + *zoom: 1; + margin-bottom: 3em; +} + +#site_footer .sitemap_directory .footer_sitemap_item { + margin-bottom: .6em; +} + +@media (min-width: 600px) { + #site_footer .sitemap_directory .footer_sitemap_item { + margin-bottom: .2em; + } +} + +@media (min-width: 1024px) { + #site_footer .sitemap_directory .footer_sitemap_item { margin-bottom: .2em; - margin-left: 10%; } } + margin-left: 10%; + } +} + #site_footer .sitemap_title { - color: white; - font-weight: 600; - text-transform: capitalize; - font-size: 1.2em; - letter-spacing: -.01em; - margin-bottom: .3em; } - @media (min-width: 600px) { + color: white; + font-weight: 600; + text-transform: capitalize; + font-size: 1.2em; + letter-spacing: -.01em; + margin-bottom: .3em; +} + +@media (min-width: 600px) { #site_footer .sitemap_title { - font-size: 1.1em; } } - @media (min-width: 1024px) { + font-size: 1.1em; + } +} + +@media (min-width: 1024px) { #site_footer .sitemap_title { - font-size: 1.3em; } } + font-size: 1.3em; + } +} + #site_footer .sitemap_block { - text-align: center; - width: 100%; } - @media (min-width: 600px) { + text-align: center; + width: 100%; +} + +@media (min-width: 600px) { #site_footer .sitemap_block { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - width: 25%; - float: left; - padding-left: 0.83333%; - padding-right: 0.83333%; - text-align: left; } } + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + width: 25%; + float: left; + padding-left: 0.83333%; + padding-right: 0.83333%; + text-align: left; + } +} + @media (min-width: 600px) { - #site_footer ul.subnav { - margin-bottom: 1em; } + #site_footer ul.subnav { + margin-bottom: 1em; + } + #site_footer ul.subnav li { - padding-left: 1em; - text-indent: -1em; - margin: .1em 0; } } + padding-left: 1em; + text-indent: -1em; + margin: .1em 0; + } +} + #site_footer ul.subnav a { - color: #a5a6a7; - text-decoration: none; - font-size: 1em; } - @media (min-width: 600px) { + color: #a5a6a7; + text-decoration: none; + font-size: 1em; +} + +@media (min-width: 600px) { #site_footer ul.subnav a { - font-size: .85em; } } - @media (min-width: 1024px) { + font-size: .85em; + } +} + +@media (min-width: 1024px) { #site_footer ul.subnav a { - font-size: .95em; } } + font-size: .95em; + } +} + .no-touch #site_footer ul.subnav a:hover { - color: white; } + color: white; +} /* --- end SITE MAP --- */ /* --- LOWER FOOTER --- */ .lower_footer { - overflow: hidden; - /* --- end LOWER FOOTER --- */ } - .lower_footer .nav_container { + overflow: hidden; + /* --- end LOWER FOOTER --- */ +} + +.lower_footer .nav_container { margin: 0 auto; position: relative; left: 0; width: 100%; - margin-bottom: 2.5em; } - @media (min-width: 769px) { - .lower_footer .nav_container { + margin-bottom: 2.5em; +} + +@media (min-width: 769px) { + .lower_footer .nav_container { padding-top: 1em; - position: absolute; } } - .lower_footer nav { + position: absolute; + } +} + +.lower_footer nav { text-transform: uppercase; text-align: center; margin-left: auto; margin-right: auto; font-size: .9em; - color: #a5a6a7; } - .lower_footer nav a { - color: #a5a6a7; - text-decoration: none; } - - .no-touch .lower_footer nav a:hover { - color: white; } - .lower_footer nav li { - margin: 0 .6em; - display: inline; - line-height: 2em; } - - .lower_footer nav li + li:before { - margin-left: .6em; } - - .lower_footer .credits { + color: #a5a6a7; +} + +.lower_footer nav a { + color: #a5a6a7; + text-decoration: none; +} + +.no-touch .lower_footer nav a:hover { + color: white; +} + +.lower_footer nav li { + margin: 0 .6em; + display: inline; + line-height: 2em; +} + +.lower_footer nav li + li:before { + margin-left: .6em; +} + +.lower_footer .credits { color: #a5a6a7; width: 100%; font-size: .9em; text-align: center; - position: relative; } + position: relative; +} - .lower_footer .credits > span { - display: block; } +.lower_footer .credits > span { + display: block; +} - .lower_footer .credits a { - color: #a5a6a7; - text-decoration: none; } +.lower_footer .credits a { + color: #a5a6a7; + text-decoration: none; +} - .no-touch .lower_footer .credits a:hover { - color: white; } - @media (min-width: 769px) { +.no-touch .lower_footer .credits a:hover { + color: white; +} + +@media (min-width: 769px) { - .lower_footer .credits { + .lower_footer .credits { float: right; width: 20%; - text-align: left; } - - .lower_footer .credits > span { - display: block; } } + text-align: left; + } + .lower_footer .credits > span { + display: block; + } +} .social_icons { - display: inline-block; } + display: inline-block; +} - .social_icons .icon { +.social_icons .icon { display: inline-block; overflow: hidden; height: 32px; width: 32px; vertical-align: middle; - cursor: pointer; } + cursor: pointer; +} - .social_icons .icon img { - position: relative; - top: 0; - width: auto; } +.social_icons .icon img { + position: relative; + top: 0; + width: auto; +} - .social_icons .icon.addthis_button_facebook_follow img { - left: 7px; } +.social_icons .icon.addthis_button_facebook_follow img { + left: 7px; +} - .social_icons .icon.addthis_button_twitter_follow img { - left: -54px; } +.social_icons .icon.addthis_button_twitter_follow img { + left: -54px; +} - .social_icons .icon.addthis_button_youtube_follow img { - left: -120px; } +.social_icons .icon.addthis_button_youtube_follow img { + left: -120px; +} - .social_icons .icon.addthis_button_instagram_follow img { - left: -187px; } +.social_icons .icon.addthis_button_instagram_follow img { + left: -187px; +} - .social_icons .icon:hover img { - top: -33px; } +.social_icons .icon:hover img { + top: -33px; +} - .social_icons .icon + .icon { - margin-left: .5em; } - @media (min-width: 769px) { +.social_icons .icon + .icon { + margin-left: .5em; +} - .social_icons .icon + .icon { - margin-left: 1.2em; } } +@media (min-width: 769px) { + + .social_icons .icon + .icon { + margin-left: 1.2em; + } +} - .social_icons .all_icon { +.social_icons .all_icon { height: 32px; width: 32px; position: relative; vertical-align: middle; - color: #a5a6a7; } + color: #a5a6a7; +} - .social_icons .all_icon span { - text-decoration: none; - font-size: 1em; - font-weight: 600; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - line-height: normal; } +.social_icons .all_icon span { + text-decoration: none; + font-size: 1em; + font-weight: 600; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + line-height: normal; +} - .social_icons .all_icon:hover { - color: white; } +.social_icons .all_icon:hover { + color: white; +} /* button recolor */ .nav-pills > li.active > a, .btn-primary { - background-color: #069 !important; - border-color: #069 !important; - border-radius: 4px; + background-color: #069 !important; + border-color: #069 !important; + border-radius: 4px; } .mudrod-navbar { From e25d8a8226915945e9420c7f8049d600863d3ce5 Mon Sep 17 00:00:00 2001 From: Frank Greguska Date: Mon, 12 Jun 2017 16:14:56 -0700 Subject: [PATCH 07/33] removed JPL specific configuration and added empty placeholders where they would go. also updated side nave and sort by box --- web/META-INF/resources/css/footer.css | 19 + web/META-INF/resources/css/index.css | 437 ++---------------- web/META-INF/resources/css/main-header.css | 19 + web/META-INF/resources/css/styles.css | 105 ----- web/META-INF/resources/images/logo_nasa.png | Bin 7900 -> 0 bytes .../logo_nasa_tribrand_colorwhite_rgb.png | Bin 28434 -> 0 bytes .../resources/images/social_media_sprite.png | Bin 3375 -> 0 bytes web/META-INF/resources/index.html | 63 ++- web/META-INF/resources/js/app.js | 38 +- web/META-INF/resources/js/controllers.js | 1 - .../resources/partials/datasetResults.html | 4 +- web/META-INF/resources/partials/footer.html | 19 + .../resources/partials/main-header.html | 19 + .../resources/partials/metadataResults.html | 61 +-- .../resources/partials/navbar-search.html | 2 +- 15 files changed, 185 insertions(+), 602 deletions(-) create mode 100644 web/META-INF/resources/css/footer.css create mode 100644 web/META-INF/resources/css/main-header.css delete mode 100755 web/META-INF/resources/css/styles.css delete mode 100755 web/META-INF/resources/images/logo_nasa.png delete mode 100644 web/META-INF/resources/images/logo_nasa_tribrand_colorwhite_rgb.png delete mode 100755 web/META-INF/resources/images/social_media_sprite.png create mode 100644 web/META-INF/resources/partials/footer.html create mode 100644 web/META-INF/resources/partials/main-header.html diff --git a/web/META-INF/resources/css/footer.css b/web/META-INF/resources/css/footer.css new file mode 100644 index 0000000..7e0732e --- /dev/null +++ b/web/META-INF/resources/css/footer.css @@ -0,0 +1,19 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 Unless + + required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +/* + +This file can be used to provide customized css for the customized footer provided in partials/footer.html for the MUDROD website. It is currently left empty. + +*/ \ No newline at end of file diff --git a/web/META-INF/resources/css/index.css b/web/META-INF/resources/css/index.css index aff33d8..3257db0 100644 --- a/web/META-INF/resources/css/index.css +++ b/web/META-INF/resources/css/index.css @@ -7,7 +7,7 @@ html, body { body { font-size: 14px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - background-color: #2a6496; + background: url('../images/OceanWave.jpg') no-repeat scroll 0 0 / cover transparent } .fixed-table-body { @@ -22,7 +22,6 @@ h1, h2, h3, p { .toolbar { background-color: #2276ac; - /*padding: 25px 0 60px 0;*/ height: 60px; } @@ -52,27 +51,6 @@ a:focus, a:hover { text-decoration: none; } -header .site-logo { - height: 40px; - float: left; - line-height: 40px; - font-weight: 300; - font-size: 26px; - -webkit-transition: background 0.2s ease-in-out; - -moz-transition: background 0.2s ease-in-out; - transition: background 0.2s ease-in-out; -} - -header .site-logo-org { - font-family: 'Open Sans', sans-serif; - content: 'Earthdata'; - display: block; - font-size: .475em; - font-weight: bold; - text-transform: uppercase; - line-height: 1em; -} - b, strong { font-weight: bold; } @@ -82,9 +60,8 @@ a:link, a:visited { } .view-area { - background-image: url('../images/OceanWave.jpg'); - background-repeat: repeat-y; - background-size: cover; + /*background: url('../images/OceanWave.jpg');*/ + /*background-size: cover;*/ line-height: 1.42857143; width: 100%; } @@ -95,7 +72,6 @@ a:link, a:visited { width: 80%; margin: 200px auto 200px; color: #fff; - /*background-color: rgba(17,17,17,0.8);*/ border-radius: 6px; box-shadow: 0 0 20px 0 rgba(17, 17, 17, 0.7); } @@ -118,6 +94,17 @@ a:link, a:visited { margin-left: .5em; } +.rankoption { + background-color: white; + color: #2980b9; + float: right; +} + +.autocomplete { + overflow-y: auto; + height: 15em; +} + .toolbar .form { display: inline-block; } @@ -268,28 +255,25 @@ a { .sidenav { height: 100%; font-size: 10px; - z-index: 1; - top: 0; - left: 0; - background-color: lightsteelblue; - overflow-x: hidden; transition: 0.5s; - padding-top: 3px; - margin-bottom: 17px; - word-wrap: break-word; } .sidenav a { padding: 8px 8px 8px 32px; text-decoration: none; - font-size: 1.6em; - color: lightslategray; + font-size: 1.5em; + color: #2980b9; display: block; transition: 0.3s; } .sidenav a:hover, .offcanvas a:focus { - color: #f1f1f1; + color: #8ab9e7; +} + +.sidenav h4 a{ + padding: 2px 8px 0 10px; + color: white; } .no-gutter > [class*='col-'] { @@ -346,10 +330,6 @@ a { list-style: none; } -.sidenav .heading-t4 { - padding: 2px 8px 0 10px; -} - .heading-t4 { background: #fff; border-top: 6px solid #738dca; @@ -390,8 +370,7 @@ a { border-radius: 14px; font-size: 14px; line-height: 20px; - padding: 1px 15px; - padding-right: 35px; + padding: 1px 35px 1px 15px; width: 100%; background: #f3f3f3; box-shadow: none !important; @@ -410,386 +389,24 @@ li:hover { background-color: #f9f9f9; } -.serch-ul { +.search-ul { position: absolute; top: 100%; z-index: 1000; - display: block; min-width: 195px; list-style: none; padding: 5px 0; margin: 2px 0 0; - box-shadow: 0 6px 12px rgba(0, 0, 0, .175); -} - -/* -* _footer -* -* Site footer -*/ -/* --- GLOBAL FOOTER STYLES --- */ -#site_footer { - position: relative; - width: 100%; - bottom: 0; - padding: 1em 2em 1em 2em; - margin: 0 auto; - background-color: black; -} - -#site_footer .gradient_line { - margin-left: auto; - margin-right: auto; - content: " "; - width: 100%; - height: 1px; - clear: both; - background: #61b6fd; - background: -moz-linear-gradient(left, transparent, #61b6fd, transparent); - background: -webkit-linear-gradient(left, transparent, #61b6fd, transparent); - background: linear-gradient(to right, rgba(0, 0, 0, 0), #61b6fd, rgba(0, 0, 0, 0)); - width: 90%; -} - -@media (min-width: 769px) { - #site_footer .gradient_line { - width: 50%; - } -} - -/* --- end GLOBAL FOOTER STYLES --- */ -/* --- UPPER FOOTER --- */ - -.upper_footer .share, .upper_footer .footer_newsletter { - text-align: center; - padding: 1.69492%; - /* margin-bottom: 3em; */ - width: 100%; -} - -.upper_footer .share h2, .upper_footer .footer_newsletter h2 { - font-size: 2em; - font-weight: 600; - margin-bottom: 0.6em; - color: white; - letter-spacing: -.035em; -} - -@media (min-width: 600px) { - .upper_footer .footer_newsletter { - width: 48.71795%; - float: left; - margin-left: 0; - margin-right: -100%; - } -} - -@media (min-width: 769px) { - .upper_footer .footer_newsletter { - width: 40.67797%; - float: left; - margin-left: 8.47458%; - margin-right: -100%; - } -} - -@media (min-width: 600px) { - .upper_footer .share { - width: 48.71795%; - float: left; - margin-left: 51.28205%; - margin-right: -100%; - } -} - -@media (min-width: 769px) { - .upper_footer .share { - width: 40.67797%; - float: left; - margin-left: 50.84746%; - margin-right: -100%; - } -} - -/* --- end UPPER FOOTER --- */ -/* --- SITE MAP (middle footer area) --- */ -#site_footer .sitemap { - margin-bottom: 3em; -} - -@media (min-width: 600px) { - #site_footer .sitemap .grid_layout { - width: 100%; - } -} - -@media (min-width: 64.063em) { - #site_footer .sitemap .grid_layout { - width: 97%; - } -} - -#site_footer .sitemap_directory { - overflow: hidden; - *zoom: 1; - margin-bottom: 3em; -} - -#site_footer .sitemap_directory .footer_sitemap_item { - margin-bottom: .6em; -} - -@media (min-width: 600px) { - #site_footer .sitemap_directory .footer_sitemap_item { - margin-bottom: .2em; - } -} - -@media (min-width: 1024px) { - #site_footer .sitemap_directory .footer_sitemap_item { - margin-bottom: .2em; - margin-left: 10%; - } -} - -#site_footer .sitemap_title { - color: white; - font-weight: 600; - text-transform: capitalize; - font-size: 1.2em; - letter-spacing: -.01em; - margin-bottom: .3em; -} - -@media (min-width: 600px) { - #site_footer .sitemap_title { - font-size: 1.1em; - } -} - -@media (min-width: 1024px) { - #site_footer .sitemap_title { - font-size: 1.3em; - } -} - -#site_footer .sitemap_block { - text-align: center; - width: 100%; -} - -@media (min-width: 600px) { - #site_footer .sitemap_block { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - width: 25%; - float: left; - padding-left: 0.83333%; - padding-right: 0.83333%; - text-align: left; - } -} - -@media (min-width: 600px) { - #site_footer ul.subnav { - margin-bottom: 1em; - } - - #site_footer ul.subnav li { - padding-left: 1em; - text-indent: -1em; - margin: .1em 0; - } -} - -#site_footer ul.subnav a { - color: #a5a6a7; - text-decoration: none; - font-size: 1em; -} - -@media (min-width: 600px) { - #site_footer ul.subnav a { - font-size: .85em; - } -} - -@media (min-width: 1024px) { - #site_footer ul.subnav a { - font-size: .95em; - } -} - -.no-touch #site_footer ul.subnav a:hover { - color: white; -} - -/* --- end SITE MAP --- */ -/* --- LOWER FOOTER --- */ -.lower_footer { - overflow: hidden; - /* --- end LOWER FOOTER --- */ -} - -.lower_footer .nav_container { - margin: 0 auto; - position: relative; - left: 0; - width: 100%; - margin-bottom: 2.5em; -} - -@media (min-width: 769px) { - .lower_footer .nav_container { - padding-top: 1em; - position: absolute; - } -} - -.lower_footer nav { - text-transform: uppercase; - text-align: center; - margin-left: auto; - margin-right: auto; - font-size: .9em; - color: #a5a6a7; -} - -.lower_footer nav a { - color: #a5a6a7; - text-decoration: none; -} - -.no-touch .lower_footer nav a:hover { - color: white; -} - -.lower_footer nav li { - margin: 0 .6em; - display: inline; - line-height: 2em; -} - -.lower_footer nav li + li:before { - margin-left: .6em; -} - -.lower_footer .credits { - color: #a5a6a7; - width: 100%; - font-size: .9em; - text-align: center; - position: relative; -} - -.lower_footer .credits > span { - display: block; -} - -.lower_footer .credits a { - color: #a5a6a7; - text-decoration: none; -} - -.no-touch .lower_footer .credits a:hover { - color: white; -} - -@media (min-width: 769px) { - - .lower_footer .credits { - float: right; - width: 20%; - text-align: left; - } - - .lower_footer .credits > span { - display: block; - } -} - -.social_icons { - display: inline-block; -} - -.social_icons .icon { - display: inline-block; - overflow: hidden; - height: 32px; - width: 32px; - vertical-align: middle; - cursor: pointer; -} - -.social_icons .icon img { - position: relative; - top: 0; - width: auto; -} - -.social_icons .icon.addthis_button_facebook_follow img { - left: 7px; -} - -.social_icons .icon.addthis_button_twitter_follow img { - left: -54px; -} - -.social_icons .icon.addthis_button_youtube_follow img { - left: -120px; -} - -.social_icons .icon.addthis_button_instagram_follow img { - left: -187px; -} - -.social_icons .icon:hover img { - top: -33px; -} - -.social_icons .icon + .icon { - margin-left: .5em; -} - -@media (min-width: 769px) { - - .social_icons .icon + .icon { - margin-left: 1.2em; - } -} - -.social_icons .all_icon { - height: 32px; - width: 32px; - position: relative; - vertical-align: middle; - color: #a5a6a7; -} - -.social_icons .all_icon span { - text-decoration: none; - font-size: 1em; - font-weight: 600; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - line-height: normal; -} - -.social_icons .all_icon:hover { - color: white; } /* button recolor */ .nav-pills > li.active > a, .btn-primary { - background-color: #069 !important; - border-color: #069 !important; + background-color: #069; + border-color: #069; border-radius: 4px; } .mudrod-navbar { - margin-bottom: 5px !important; + margin-bottom: 0; } diff --git a/web/META-INF/resources/css/main-header.css b/web/META-INF/resources/css/main-header.css new file mode 100644 index 0000000..8494e09 --- /dev/null +++ b/web/META-INF/resources/css/main-header.css @@ -0,0 +1,19 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 Unless + + required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +/* + +This file can be used to provide customized css for the customized header provided in partials/main-header.html for the MUDROD website. It is currently left empty. + +*/ \ No newline at end of file diff --git a/web/META-INF/resources/css/styles.css b/web/META-INF/resources/css/styles.css deleted file mode 100755 index f74ff70..0000000 --- a/web/META-INF/resources/css/styles.css +++ /dev/null @@ -1,105 +0,0 @@ -.post-wrapper{ - float: left; - width: 100%; - margin: 5% 0 0 0; - padding: 0 0 0 0; -} - -.blog-post-label{ - float: left; - width: 100%; - margin: 10% 0 0 0; - padding: 0 0 0 0; - text-align: center; - font-weight: bold; - font-size: 16pt; -} - -.blog-post-outer{ - float: left; - width: 60%; - margin: 2% 0 2% 20%; - padding: 1%; - background: #e0e0e0; - border-radius:6px; - -moz-border-radius:6px; /* Firefox 3.6 and earlier */ - border: darkgreen solid 1px; -} - -.blog-intro-text{ - float: left; - width: 100%; - margin: 0 0 0 0; - padding: 0 0 0 0; - text-align: center; -} - -.blog-read-more{ - float: left; - width: 100%; - margin: 2% 0 0 0; - padding: 0 0 0 0; - text-align: center; -} - - - -.blog-entry-wrapper{ - float: left; - width: 100%; - margin: 1% 0 0 0; - padding: 0 0 0 0; -} - -.blog-entry-outer{ - float: left; - width: 60%; - margin: 2% 0 2% 20%; - padding: 1%; - background: #e0e0e0; - border-radius:6px; - -moz-border-radius:6px; /* Firefox 3.6 and earlier */ - border: darkgreen solid 1px; -} - -.blog-comment-wrapper{ - float: left; - width: 50%; - margin: 2% 0 2% 25%; - padding: 1%; - border-radius:6px; - -moz-border-radius:6px; /* Firefox 3.6 and earlier */ - border: darkgreen solid 1px; -} - -.blog-entry-comments{ - float: left; - width: 96%; - margin: 2% 0 2% 2%; - padding: 1%; - background: #f5e79e; - border-radius:6px; - -moz-border-radius:6px; /* Firefox 3.6 and earlier */ - border: darkgreen solid 1px; -} - -.blog-comment-label{ - float: left; - width: 100%; - margin: 1% 0 0 0; - padding: 0 0 0 0; - text-align: center; - font-weight: bold; - font-size: 16pt; -} - -.rankoption{ - float:right; - margin-top:5px; -} - -#jpl-banner a { position: absolute; text-decoration: none; } -#jpl-banner i { visibility:hidden; } -a#nasa { top: 15px; left: 10px; width: 85px; height: 80px; } -a#jplhome0 { top: 35px; left: 95px; width: 280px; height: 30px; } -a#caltech { top: 65px; left: 95px; width: 280px; height: 20px; } \ No newline at end of file diff --git a/web/META-INF/resources/images/logo_nasa.png b/web/META-INF/resources/images/logo_nasa.png deleted file mode 100755 index 4c1666c89b525b76a6db32e4e68a5cb1bbc24342..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7900 zcmbVxXH-+&)^4cMdl5v0NUurgRYEoN4$=%IKnNrd0)(Olq)3-0f=E$1(ve<*2uMdj z=}J{Wq$ASw;yLF%_x||C_v7v{_Nw!FW?6In*n7sB8tc*1aMJ()0D9PMZS%`M;qt{( zQC_xuJ>1~Sjti$_i?hJERRDm@9cgKcvo$hQ zcE$KeIscWB!u$AMq5%NaTXs5AWlR_E*NM0sqCTd^!HREDhxQmk17}2K={C zwnnCWS{N*XPfiLX=?anu@yUawz%sH53JMZ@5D*w74T4C6A(CJPWf_Pv2*mfF2Y9Is z>*lU(uC4nYU6(U8peGLJt1K-Y6ci*CBqN2vdPswnl$8E*Kp>Kr5|aMGXq+=%677HU z9|moNzbh8$i$h}2e1938T`&PSHQ=SC|8~L0*U0F<#AyHj1nM$m(s*ZIX|NPX+Q;Xw zU;mQ!$C)GkuNnWNw7+GrFGAWJ;g1Qxx?Y}#`^|sAm$Ccb75x>wv_{zki@ZD(XK!tc zYk&^|je}{c0WWu?+>ma{AX!Ba7_1-*Qhe9JHUf(bM7Zf@9z91hiugVMomd~CCQeThdvnoHhZ^`Vf*%KvKoGk zkZw)$bcL3Q$H$N~hL;I?=Dm`%&O?A0kgT@xZM;##ePK|YySLVm@Au^iZg(b*`8M1s z+D|WnFY%JYnogn|bFF>y0!1xUp9My>k7 zNjw&)oZJtXYZBI}E34D)oa(tLUZnW-8Dew3eFtA>01e?2Z)|);2E6hC1UFw;L&|+oD%}+8yS&UZBsRT8PT(yZDvV)G#RH!#$oAZzHn0cA}YYt6Hp3`Po0A&VS$Gcg$xC#=Lym zmTBa2U&rA^v}`>Q_)(sE;kD9mxX_{=5fbx9E^AVXNrzSx{VzxTfPc}e5-1d~^9v?V_;?x|-*o{Zkay-$%mYbOw~ z3GYsuBOf04wYxL-qpI!zIKsuWVZUGJkPRtr9QX**OPCuS;NoLu#?m@xZ5NE#B0~M# zvD_*15+C5d5^k3T*3yB(ItC%tpPuBzhv}?we_iuzQ^HhUJlfuo3m?sCvvh&>#GDEb zJ>`S0DAv3SLCVt-UCI?Ay|Kx^JmZq@Kc3T>E{x+3-`e4+r z)+7bn66pJ6()+C&_a%{TSJw-`I}uM$-so^U}4X-qUSg*{+rU zwZKD4aJIm8Au79GM?nG*Q%erwu_Y`_j{qw+WbV4ckxJ*{jZ^4!A0a}oQ#FIIZWcN7-_z?Z@;e7JnBxGn;Ja)7rR*-V8C_c{O8Uw+Tae)@ol@h zJ0DTyY#ipLNkz`jH*wGQX)^>KQOs`4qVAWJTW!g9+VIF#-+&D@U6*as?zW!@3-Zj` z9Y439Ec1Q)@wzQ8)D95`;Nbt|T292hTJ(3QZ$X+%r*>XlNZDgQ-!h&j4soA$eLk2g z7DJ3ai0>#?G&nqxnDcY4=;*6#pAPU0(SnPX!`@Kq+P+z<^GEz)m^hvPO-D(?L&~WX zC?Btus~BWvq0PBt@nGB|fo|uiYQAlD>0lFf!@hr~p)W;0rD-46>zfeKTLW96Eg(7? zRzJNqDV(c2GQZRqw*Pv&vJ7S!FxM%arnWOiJKNxO26c4f_=5Vl`P{MyDLB`88o$`BD&Dx-0>wHUZmUKklh^lj(!_RwC6___V66T!MK? z$Dl*#UDCm>D&CT*gLzNyz+#(jm-L>5+EZW@#g&jSXCjKpih)+jWL}7VSJ~5$lty4c zqUIYV-42(a?Y-J9CjcF}8G;}rewID0K?XswnDSjLAad0ToSm9ZBlvGFHe1V8FU|st zhL^^&uB^kx0V1qbJcVSOjhtK}cjO<~S$1MmKl*lM5H?UpQCcUYF5pjWzQD(KO$d~J z>0FsVA^C?xk|DHG#0h?hXs3>n`>)u)R&asBEEV2t_MTpR6aD$khrwCSQ`u2vJ>ey8 zL!Xs z>h$$!St-1aCngQ@Fl8HH2sr}h2`S7MR{E>Fbf(wa=+KNA>(YaHYLlf7xoP2S3gX38DAgd5PET3qMkX=Ofyv?rC+cx0GnE$J9$AllcRA` zs3}mCLF-B$OjlC&wo2Y`eD|?kLwWnQqE*5ji>g69cYz(^i*y&b{?M&HCX7Y`q_qCP z0s5fhjD&uJ*?{cXlmx`~EjIPh{Dj>cLRZ0Q!X|DyvfBf9S|7r7Q z=`=K=?YfX2RZaI~+3sp`dJ~Q!Dopmtxz~p9w{Z@TWPtc3)~dXhk~!2Y2kdw~ z5Hu{T_tDeFXuH8{3zQEue)Gn?DnAv{7o^f>$7Eu$$T^d)+VTf!SD3vxB%Fjt#myi} zv#Ym+&a?tV)*imcA&E?bV}SudLy@2Ln#OVhPVA%a0`6HCC`+!&MorOE-l6=%{IL9i zXF7+AeW9FeV$begri2_ZUjPu+^E|AKe?URkgS|c(IyUp*?N!0UJbwmj<||A2 zXdUBpCuw24$!lK0$j!Vl6-O!o+jDI4>laub*D~+=;wYz}?{MYCnUiaa%E8%a-jj!e za^s>j-!>g4YS1EFIQ>4@f4L#I8r!F>Eeq z?%j(qJ~Nxlq$rIX)gh1z0h~jcD?t=kI5n@@1d}aa8A1!`45zNSur6q^1-&aqpn+qzYrGGa0{+qR|=x?357W?_D-4;XKVIjm zz3V)@wjVlkucpr9du#U15fM{?gc)~0DUz8lDMWLI09fJ530>AlXnT|SN_PEl@#tToUyWH(RT5V$H8urvOkC zJ#)igfA?#yF6K-u@qBaHrL)-iMWv<~_u3KFAa4!RIOI*QX3koNa)DHpm1`!Lqz zt>|yY_*lZ+4E(rTk-)hTJ~X6PAIso^miL`7rz{s$%a-YkOf@L8W+n|_@)PZUA$euy z*fNdZ5qCxQM=l_NA399Y=#U8bKBAj^f>olZyrWftUKpU14%jNmt)yW|mtepiDv~A5 z+rCjd25E{@xd_DazqX}@*6SxjEDmNAUMBe?FvdLC<+`+gr z4ezZuc176hIE%JNXzm3!kgMX9A*=e(wR_7?Qk>qJH-sUTNF^v?LU(O|HpiPcCdW?> zesmdwe~=E?U(|1&==3(_-+Hr9BCGCD<78zKck9poxWczV`yHi8k~3i=4}v<+G!*R1 zIbTy8uf*ckH?|2k^5nF@0?2}$SAw#sYGjjE7zA9XABpdtR#$&E)ljX@Eczin6~kQC zQu6IX^z=*0Y}5elyZ7}9i!<$&fWwP3^Wl~1StBx|^4oiPdY~a<1qM z(v2z5@uPcC0DAu<1i$k57O_0=herE4X@PZI*M}PfX6KcYR;+nhcBi+*rk?RsnL+Fe z#esoVdJ*23q+{j?cVPmLYw(2J4Aq-q<|>NYHZ-cfqOm|N z)!3XvQphI6xOW4|!WO?a%HslFo*T@dgA-hm&FV!rn?|I%75D)Pf~7)^9UCU%W-lSF znJ-QVE#b3I)f>_*h8`K1M1glbXbeR~Y%H}JIPe>-anD^yF8Ah02PV$kBz(0`U>|4}J6}3IKYaZmkk%Ul1)F#EpN9j7j+JB7;-M;xqP*#zs zwl{5xibO@AmWl=Ym#OK~M6a;z5ue$m99w*|v7k-q+`Q3YqL;gECbE#EV-^n>Lefxe z1{HB$`*}S`S;}(f&q)#z^{H5|U>mv~Jx^&>Stz`Ov(?3?^;5eGPdCjaf?t0I<~vDqF=pLIxP`2)O{boE)ZpqQC!n5ar} zuPVsMp={~;mn(urw{{c-XxScrUtYAUbaI=*tT# zxgPA7LA})M4AeJ7z{2*1JIVb&GC6&Jv$%d&;0EX)})~I zyPM{vDIrNyL}@(!q4!h9SHcXWpUB3F1M^JO0yZE@HQIJn&Ncj#QIOwh;)|UFscL*x z70oJRk?LGpz^&2ZFPd>G%;|QPpb|ubo9xp`tHu+1hVwL9JvL+$$Md=zGDDl8+tOYB zoW%&;^nos!2W~J8t7I=$!DQ&rlQ6tfrr*IG9*S&Ar$-tQ>kVkWI*-mXo;Zy2Tv*eC9FR<>_ zzf*Ta0M5$IurC>#8&V{A&a?3_<2)RM8~uAeMP#{yy-jFu3$(Kr3I?wI@KAdnK^jWon3PA^?vz*G~HuQ$h$uXg4c00hQk21In1JP~pP9zIbtp%`d4}+z+!wU8;a@ zDaP;MOUD4&DjqU=xONqPO7|;H4rJ)Pbv&KJ?yWJUoIgDWDKVN8>}a(Kx?A423Zuv> zK?m(}nC1SKX|A>K+6wnaIag#AUhsF+xgv_+gsl^qARQwrvB*RCq&1Qt>s_Pt~p;b_#hek?1~aq}j3-*-Do z-Zz!6ZzyqcW+4Qiy^9oHs~x_zDoI&8=I-I7;=@hg@%!a45WD391>vCoSVPFs#6)i2 zjdXXM^kE3nq&lNY@?0_W>8M{8`ThjjdnRy)I1rB$P)l?2FO;bS`m#?g;2ISQcSvvK zUz0yR?$*(hm;4+Ynd@af-vVEf^N{{(_Xg?vY2`X*?_>$&QIGW`rX?cJ&yTV{35yG7 zLdKM5z8CF?vW9MW^m1QC%5Zr^7lXu*sNY5h#^`{o2*NN#9x={Z$==ukt)iZzl&Uga zS{qPI_^7KyN-?N)4&o79Cs=Cw=X5KhTNx_-R{}e{FIu(UD z;Wa3KPL8fkM~BgXNK@&9=~&MyuvgD-v@Q0~vS0=QtO5zcBF5$qCmSc`TnHqQ*FFSe zNg1j9xSz9fvsC_;Y6KQk{&#|d!Mq?Dg^UZ`2Mx(tGL&KGS7@yX?Kl2&+kGRlZHUNznKugmN1 zrGu(g0eauo8vvg?E`Q#Q+O2M{a+C(Li3DfUXe*T20{TjksWk4>QmqYR8xT$fR`Olh zYR+y-a#)j@?kNd3V*0&>H&50_*eCp$7tbHF_i$dY&ZPz+(T8-p1m?TYw6<(&G4`=O zhvA>8Z_)C`Gp1I`@?&g7ARdZ^o9TbzV)ng(8IGyfXboYJC?<)%Vid>Q#IVKzXI>G1 z!yBz1MiFTeOM53n_Rx>ZqtBhy2@GR7AScbqr{o}CCCA3!7fw)?1KyU?j-1bEz0fZg zu+MNfRD|Qly#=BcWeVZJ8@VDc=O-2`Bd9`iN{muAgkWCwFrffI6IUA^Ah9Gaf)%4M z*dvKYaOAym1dzE~~>cS+Fh9=CPtIDF=Di zf|2iTKzLBGx%I{*yw@^aOmti{GV*TmfiE2vfg4|?&>a-j~Bs~g8 zJt*uUUFEYz{-w^D7wtDv{Zf|M<&t5Na#~;F^P=F;k~P^@ncmGZXq&asQs^_frUhOl zzg#J|yOVQi7F&)U+xSnJM3=1SWg_sc%glA)_J=R;Km^&@Z=n?#I_XSMQ}iq8+@~X& zHA@VzbmSIiqk`_63F9Il#}k)5UGnKw!ZHCE`11YCXOoBX^u7V2z0_%J`R#o_Aw;|(-P z!ea#pIR_V-Y*#1UHy^-PnriQ~V7x#_%n$U_H|qwH7?W1}>1Ss}oMf$3@IEd9Oh%E# zZv@ep#C2m%p8yhj2yd>#I*q;5wyo{?+xxh5doiObPStu zfIie%9X(pd4?2=urN#rYN7YGrNd%thr^<_(5mNT5d>i< zob%+~cifMuF-Xr;&Ht=gzmi_8?l}mMmla2Z$At$214ERQ5K#mJ12=rKfw0g|{}#x9 z#eI5#vy@P?0Rv+o`}qUzm@Qxr2F68aq^xSIDkIIKZ(+uu3$)M!F*ur8K6!(I@d-Fu z>gt<-Y>D+i21e%mq(=?Sq{K!*eo_^7873J^VUVGbgtIkB$yrue-`PZ;8%Qbufai1M zc?w_#vehMaG&41~;c?_A{Ua{Vll`-rk(Brk7h4m4Qo)}c606F{6AN2dgNWG~IOz46 zS-FTgxfz(*xw%-_=!jXEm^m1kxEYz*=$V*#n7DbEn2G-?qyYFQi_aSPkw;NP?62;g z{>M*hXlrZ9!^r61;K1O(%3xt_z{t$a&CSTf!pOox|Kve$<795D>qu{IL-uEof5Z_1 z+2~svS=t&|m=phutE*>WXUk7Y`m>|I%U{=JX8CtV<~Dz^d!oqbsB6i{%)rF>pF}|Y zzcrS2)~0_94XDouG6k7|%x!I+bj<%zXK83*Yhhz(@n5?9yZOI%{4^&rGJp5|AIEEE z_8+^pu@$v{Lhu*T|ERQ4cCrL9DuQe*?5y=cqV`XhLiV4o-qz^jKPTs3BK>UnuVV)} z8vPg9&z3)Be=LPRXNd3VT6u)6LAtgU*2)$Zrhq?JnfyNx5(^9eTveRJ)H1sIM&>`c z((p0!BYcpM2fRUN50f^Dk z+<=eqpOw!%|6W%-!WO0$)=$F%0a*DM|5Nod)gNn(N7CHJR@Yn~Bq;)Ts$eiO0`lmy za{^hIIa%p-b@jOE+1P-(^xWLcdi21LtRPl)eJ&1eZrwj1%E&yI|Buij7W#HS_sd_Q zf&Z7GpUMA6XgO=6r?XDi^qJ4k(f{9e@gKtckFF$)Y@SxA)3cTPw0{3M&6Ge^|62Qx z22-OyP9;lSYa7tdJ;zV_k4^XYG4}T<^;7f5-sREN|9PGP^nY#%5Ri}YUuyq3tiP3i z$&CL0PT-&MpUMAw9}b2f^Z#u_{Tb>Hum2vz#^R%`gRV75(BNrJ{GaXiKjZ$Z@ZUS& zWBmCJU~2TQQ}Ji*zs}G<*6jbBQNEuC8_&~fcp91RAG5&B$M`?${@L@N{;EG`)zt0} ze^#bH3M2E+m%p^n+y7mw_6zOv_J7y@Q~J)_$QHozS9kwb{Y>@q{QdK2PL)Z1ZzvvT{6K*&m{RZ~2c(wSOv~s61CbYxzt0=X5=L zTmNG=|EztwX?VI{Vf_1sp6{I+P`uA647&q-?*OB_@(_D*Dn!0cleF# zIgMZ1zj6H%(Q}92xSrGarTrV%FA+U=_>Jp1jbGZoas3j}bBEu!p40fH{TtUW5j}VK zjq5p$U)sNM{Swi0hu^rK)A*(R8`m!pJ$Lwx>p6{I+P`uA647&q-?*OB_@(_D*Dn!0 zcleF#IgMZ1zj6H%(Q}92xSrGarTrV%FA+U=_>Jp1jbGZoas3j}bBEu!p40fH{TtUW z5j}VKjq5p$U)sNM{Swi0hu^rK)A*(R8`m!pJ$Lwx>p6{I+W#vq_=#z`*R7z`%AtfPwLR0RzLfh}7v60|Vpu zASoiK>^Qrh?C?cdbgIk!(*8>d{s%vNasy0MbW**pLK96)8&$2T;Zi{@8~Z`-Lft{V zH(KrW&>|Q%VB}kTtW4Z?^_RDqvg7Oy&VD$rP*RF6oo;Zpo6_6zYlgV(cB41y8K8fb zIU>_>$e)H^8sf{JMG)`RQ}N>XBZmUg?88%moo)G9P%1rt77{~mx;)x%!?-AKfpmKP>9)vxc@d zU8DXSfnQpU)E$8;MACe0q8_{M?p|he^yF$iii2i$^bOrAB6Hh@UB@azEGWCak?|Ou ziD0`7bJv!giBL7}RHd0HmcfezqKwFSMk2@4v(;XFGht5GGER!OkH9{@pk!%UO^Pf zxs3WTH30NbuRP4DYh;wBy9Rt!sqn+@xA(+IpH^}8Ys8ygnTU!#A-YYJAYO7qcC-NI zEFF?h!TX+2KABdhf#o>0O5nvH)chcn{Gbolrb)HJOk@&bx*QxMU6Mw`OnBQfS(=r3 z0b$X%E-je(z1(03*loqar9>{h5}7|Ki;jeWZ{@rXr^oNluzv?-_qsno4aG)tcj~=D zLt(I?-51c_*KO@+(P7yc5i%>>Hs;vk{EQ~R+me*){fP#T*;xrPi?)v$=*LBdt;FLZ zUwvE>9T9WQW#VY7)3jT$B$2U-tt znIOyZTEFVVGtPgy3kj3hY$jSlB-lGji3ZWrLI|DB^_6{%X^j2wh* ziI1JyI77Dp_XR%KvTV1NBGvNi-XYin-J`w7S)%63S?i5r9-@BpDZ}}p1^H-8%ZCP% zZ6yzrL^~r@6m5ke`f0*8A~%7+W`R?v)W=%*x$0LV6&?!SyeHEEnfYd)Pj9FYXxt32 z?2^lSse4*NxU>9U6l$wLF#xk*ED10-BCyU;13GK6=I=c?^;P`^qmd?pU?Ak@1|CCZ zy;53cTIRbrf)FR)l~%vF9W^NJ!UtxJw6qXYxCM!}3AU8b*QppwnQ(nrYT~=P6#l;D zAg9!nhT*&^*n-TiOI^@@n9^_59lBh~@2sGWw{l2jPf(T2sg%NZiUSw zDd5%(O0|+BlFaTJR-1^_zP*G`lxPZtYVYMTj$HDg*mVkjMHqxstiFx|)zq~LF5J^T z|6UAxWAni@2(tF8SN9RXFV$UpFf&X#cdh3T(ljV=7FL#AHtQ=PFK6;qJ*~vqS#D65 z<@p!DxAPUg6lYr=dj+icx*aa7s)aeb)~yQI8&@_FJq=YUfA#v2#MM@*t8PAotqQJI ztCXNc$WROG0<-qEPF1SpP}kvRb?4rumL;EKfft7}Vy8@SFj9DlClYpzg;mN8yNqCnIN3gsL61rOum)yzwJ+^Lc1Bmp_e zA+Qx_*y~c+21BJ1JYo?iSdHrYJ3^e=rA(FwGkBQ3+o4kzS!{<8xKSH%UxLcrSale|t)}z83bt1K@ z4y02HK)_Jv8@Ht506|vl{nPJQO}ES^ro?IJOQzh)kb?=gtB#NIl&mbEIc@4)k)m4WHXb_o{%vw5#i zU`amJ(>R+`ZUOKMq^!iFr!aaOlAR|yiqpbaY9-2s9s|du4-40~SHP!JU4J@X(73KWn>gm+LIm3rJEWn(i;DgGs9)k z#R_qN`AWbk++tsAYNE@a!nSxpF;!CiC^|@3crltB zdzN+O`G)m0c2umcLUQwJ@%^lkjhSf`Ci6lNDlxJ@ zIx{PN>sFM;Fl2zMh+0J*55!m-fu=4+z)LLXkP}l!e+NiB-Gz3k7Im}7J*o8`u7(v~ zi;kT{eRVu*S9jWo2SO4F=ECE3#ICMyZp%p z+ID|}@W3gwmj0_epeKwksvZ1vLE@mn-?P_jgyox8HNNA>njbi3$QgfMZla~WsHYtN zG$5$YN|9{+2O87BS!fw`^YQKJ+>yN7B9C&lU#p6mqaF;A2A>q+Y)gE4;|>#V26-yC<80!>PY zaBFI`r*4#}xGXSM0yhseUvU3OyxfkVX%q0RM5wEOn&!qnW8#cE9s>!jrk75E?g$Ei zT1PL{UKl+#rNHSXxul@B$rzSV^)8Y5wuGHf2Qz-6V^dkQ zDs_>C(GEY|@%|d-LhC8g(T1(4P4KB_%dyNa{3h(hDJWPo$7mx)G4(f&)DyK2&dAF8C%%iQc-P_q@;^g}jF+$qr&q{eggM#WgF!q|Elvn%7y1c{&HV z{O$dfM6%44BKlHtNyJ$h3#Cg2B1L89f_m*ESV+<|{K`wxx=(CT6A>t)LPOITSZkD@ zFcN-rn5p9lP})^?hQzeM(aahXA6J~;w`QzR-Q3U~)aSBUyD88mLR3ob&_yPWoo^8_ zu73l&lB`_fXSaTMZxgWNZ>&k}ehF1P-t;IBv)mLzRswzU(gX zL32d8>vhab9S4nM2V*k;I@`b%4}^dp61r zm0l#}F&yoQl8IH6AvC~sp_hG=6l*;@hNp!)5|1^;ITCM%XU414#!Ra_DW$jF4n{NC!G& ztI4@8P9w^DN2^cgXdy-Q$z97V5%EMoz3DkF&q55y`nMQfB27L@z*CvSo3 zWh+d7_fA)#7vIl@5PkcNkAq_Z6F9Ub0m6N z61z|qfjolRL448%VHo}arJ3U_Wnr)byR~ezL+CtjPX$)Q*D!3@vcuQtT5nwX;FNPz zRUCByJ-iGU1;;N*wqoh1`t?UCWEpQ-^c5!GHm8!Zq|ksQm+ci(-|>j{B~saqErghK zh&Q#Po|Bk0lJJxDBj=kASZ10CdwuDhX!U-4lrGgk;IBGJq`P9gWtL*zqN_)50WGyU-bepvFu4R zwXi2hN4rDdA&35Aq6pMN7b|5U; z@F{r$K|mp_#8o)Zq4@I3D3Q!bQCj{Wz-2-&%|RhQV0J=wQeqIK|I zB2^@!_*O1d2QZbozfjA%9Ox!GU+Y?9TP72$?vcg(#F~nJGYq^7iF&1A!?#9x0Iwq5 zDG5Wx`?(}BXjmP=+(Xn}-~o3rgmYh5650Gi>u&#!jzU{)3$x4O8qfvDF01=(RI6PG zdsG)BfjlY={f9yhL&8yLAI8qK$-#wg5VM{SieqCfPX?(ehm3IOEbjQt3u7uZ6I4l( zv`KZ>Z@J5xhTh+Je4(RLR|(+ska7*FN_1Xpbqo3W4e(aJh3b**G zrutZHjE<}G^|1z9dvtvt(+b&@_HE~cjH-e*Ic0*goDLf&+=g=@B*6tu@nfRc&{81B zZH!@U5QpH1IsA-Cv8Gds^^R`(AmS{Ms1XiXsuVl7qnU~A{1oMOdWe{b5u*R$QkeJU z_Tb&dMi!I{5Cr99*GGrN_}Y7bIG3n~)!P|co+z~JgA>lvGa1xOXC|8y=u&#Imxmp_ z*!%4Xij&jnYyy)pc6^tud|%sfmWN*$;|wW=euT?~#A43663;_yCqn8XV1eF?KKsxk zsA|#df)1dGvLnkzI~o+E!A?>kZ@*?eRm2w;%qT@Vsc{5 zPfuvQ5^Hl@QB)yiJ zN%09n;0b0gRE#hm;Mi)m+5N4w5#jU~LLqhuleKG_;-%iR!(>i{YG*S&eA>-xfev`b zmzXohU$z{x4&)bb=gCwJ`Mw~bRR@~CTghPw`)TWQjziLCb`>rF+qJuW7FI#oP) zY_9^Srd>POnW#DBo)hC_v#5M#)JHexT%fmy@Ad6vC@Mv=1B`d~d(zCB2*|XTWLz{b zFGZHs$5q1QL7kP@i+B-!cXYE+tIi1w5Pz9XOoj8dPNO*#U*JU468~-g-qkdsKe&AD zqwqQ1z$!9T$aqX}gE7v^lQF>~ROmt&)c>Vr7u~#?<*x z?tsIfBmDz@?U2u^IKkYnOmr?%Dw>BkeEpI=NzRWSdnQ&*ww2hC%^L|XBloT#j$xJy zcPaR8&pCadF;;nGFvcjkg~!KUOvEU&ej2^mgmtDhRzRN6Q*cne8g-gw*D>}whc{MO z6R`@KCrMbfBPRnfP~uGGBo3$q`aLqwG5B|!-yB z!sIiW%gE~H5PGV+rUt9m&P~kv7ok3?UKdi}SfyJ)=_F*hfDa}}N(%)rwL9gB&IfJW z`f5nEqq&ew1r4w5CNPlKqyQzfR8HbH$GFhQCV`_Wz(YmliGY+hn*Z5ekrzQOWFeJ!*~=%@lIAb^w-CH@g6!t8*(R7IOsu(jM*c3 z8f^vYYGZuEh7P6&ObudLF*D3TPLIjM{T4%}wxd=sNb9xe_MUyv02dR=y{UI)rlQ#|)Q&6K9U2l@L_I~;B>T(XNXi(3h?5pn9REMBlpEzaqz$?;|C zXi5rHuI}6ra5JQ@O$BWZ&H%>Dw7QXULcXpP+PBGHGT}6ZSX_6AM7^~OBhFYeP;*YR zWiUwh7l&|drKXFBam*qqj~F2qN7!P6JmYB&wP-J6GlUw&jLocb?FTUqQW`dr-AQpK z$24)!aoa$IHL@XBeikEa9l7dxm%QZqvA6JQv3rW#0zIJ}MSv zBBDiw|7Pe|u#|){u)~>JL$uv|%?gR<-z)uynLzpcika}y~Pc-RO*^hZ!38`wk(CPw3&=dr{wGieITGUUY13zhQtbpbg$mJNt9QBJCi4okTT-7-NPRJf#p0;MZdyJ z({C_H7x|4CftJYVs2F`ux6nXn)C$4a_uG4uC@RAQQ|k5A7;%S2t{ z!-q(V+ysKMFL{htSd<1<+4I)r8zMAOl4$Ib#nudc9?^9!E)$?@1^Xtu^&f_?Bkv?B zUlS}Do6U^9FjRHvS^8WRy?d6)A*e%Zo@g97*S91r%JYrbP9{2AT9X7pe#HWv{n1I4 zt*4PcVb9vAy<39tU^7GLfPu0Om7?tZNqptwCC%;+IR!vqRe)F zHm!9IX_hGgQuNy*Yogh#PlzF$aD#Exk11WK1o>&*Jnph{Z7Oq{2J?M8V$BnHtyWsQ zD$!^A?Nm%BpVO76e0m4ps?)11U2@lG1ANEIHS$e9kC{B?l6;Z#mnBK5twq++wqf-T z+3xXVyhA6f1$TICFY_}Am^5#Gak0co`9HYbmy5C;7MM&58`@g0g{h4KHh}(KinY2-v=pn zehiy%3Hj>j%E5jXc)dVF7Vk1#mN*vZ+#}uOHC42|)%zy@WA_`dsu7iim+`5R*1|0@ z8Hh6(X47M*v`#2h9?GqoRLJF(97VGO20++Wm60EJRC8bN3lycn03`2n0e91n}#{2?ymzO2F&ci)tkWtTnl*u2u@ z3P?vZum(^u(;M)OZ%(opNUl*Q?(d^a6MkvGtY8GK8gL%(`PS&hXbv{~pr+R82)O-P z74<3gHuN%=-q`ji!2cy_fdP0`ekN&Gfzdn|%#mtCw-?6uYnN=O0Ety41-c94L;$TTjhdN>$ub zq$n)~OPk6HsF({b*<+&96MnY?d%@L%B#an?k zWwD&~dP!F%9?SY>)tl=*u901pMtr7v8JJh3|712Vt+%0euU@u0etY8>1|Px}^lIXb3WK{bxqFOU=TlwzW9T z@L-60t4TJGB_VFSdp+s+Ow`zKv6MQX(>~Aaw4+Qy~N3)ox$3Kx;ECP+mSDY!ihgFfu9~(Ys5;t1d}p zWeH!&;sA$b+DpeA)}+q&DtWLr>nK&9`6^WyhEpPVOiw1@gzHvLN>m$*(cC|NcFb*B zw-2#ixkR>{g&O~ojJnzu!D+R*-E1mt3eKdf=??GjKp{XS@-c^YDJ#lB<~r2-$6~+= zSv|AK58M}8*5`Id<(s&qug*~m@(eC^X~}j6^^roNmR`LwWi(8)5}D-Sq^WsT1sr|z z25klc&FI6*$QuuJcjUahjv__Cimx5#aY^No>Pd^Y%)XCK!I@LBivSjk^9zMM?Or0} zy|(gIurQ)HEG{JM9fv>T5V}J z>pLD2xLoVRIS|E{pQL=9h2`YqN#^%=SQ%)aB#c;~YHDd&d+Z&`1&GH96Rpj0hY0)2 z@!Fyk=C{dg0_dsgimJ*wmn-r#>OB{b2|GHL4opQBo<63TLq7+5zt*1N$1o8og@NS* zrzq^8d8b+Sz)g$v5QyGYAU}`kpWF{{+8Q&MW#Bspu7z;H1Ru0EiDL@xs8bg&e@FPS znRb6uW-LQtpmhfLbhH>$Y~&VuSMG--8sdPeV?Bt9K>!Gbd40Gwsq+A@@7Ky`hyU0M zd^kHAkLQ1MS#+b07r&bo&$XEbDSbDXKD;|*m_)#}2odg`^vQ9M_seP8Djx>fT#hmd)GX$#yJZ6V7_OdShsXq!4G6D zA=Tzj6&FhqUwWOg+&w(S%3%QkbM%$cf5W8UYQH;%@9H${?rP`7_Bi+pz|&`Xz#F*& zoC%KIs@t8Cm|(6=gCZtb8~ z13^4oTB4bP3j*`-yn}=K3{u(UsF8R3YDg%VryRjJv)g+3C^t=S5S_WZUp_)*K|z7Q zH;?P0q^1;~Kx9b!t%6^XCqo{A&#)uV&0n~oOOUmimzFjsg^S=SvPlj@(MCI*>#`gV z8Rm!YSFS=e=uoLNC64sa_~lv=V^W`KWiNWkXgwrPS+%TR`0hu(oQjVWCX)f{F$c`esU z@^iN6a8^j`vc`^i1GvA!IfG2Rcxl%>>|dM?7C+0h4A!h8qCYACYx1^;x# zQggHYkXdgl*n^}u?*5e9SE|`0>fhbV^J`IXKjOEEHn?}Bv=e*DaFcLGN{r@{3-LDh zNh)B?mACjxa0N1Mcb8A(zec=ZUNw1rZ9NNeshnNC7%u_ZZ(+9(eMB=jNwXvVt}xb4 zA%druwULD$#_L1IJYO4hPy?5JU50J|u8LLF`A*YnNZX~R)Mwa$F4LxlubkD3PD?|Q zX;4lW1W|2%dmHYbHDEgpSRzs-ApjUp4g1VVdLjLvLXrXKouww z6c|mC6Dndc=y3>=IIMmxcEHAKir1&kIl5hKJ3UECvVCXIuymhi*6jT1oytU4sMF~q zGx-^woWIzi>*3@O2q$#bm)mpm%)|oG3-Bd}yWWAi z(&5X3Y+t3loJYNq#Y$dAq)t~t;2?@^$-g+PcdH2d7+{Vg2&Uqc$8${>CPZMNU9+HEJ2H?W{9ciX+v>_c3gPZ%E}q7PlbY#kxnl5uY<5?K zHH<4d-ft-*?TWm)^G!K&z*1?I$}=m&Nql8nB{ZZaH1DL>L@2SQ9Lz7zO|DH6-=W>z zO3vDFp9~brfbeldqdZ~N1K)-nXM42b*joxUqj{jt0X8pqWmM1URQhd}_X$ms3TRKE^W2XlNadvNyM?q6@ zdhDjqI6klAO_V|d!-Z%hsg(`Itid@}s2!1U!xbJI;9f+$sdCT6+U%=0s6dkPL%kNI z8G(PFjXfHUbMR&b8lm@FQ#(c)w3w>2Z}Vhpn^zx;;WFB`7o#7lMIw5mo46Bmj8yMe zg>b($nv4j090GO)zLJQzQZmE~JXbJ?knx-Ih2oTY`J1FGOFA6$t5oq>H3%j>Jl2mhzR%4B|nwCLV zeR^);pL!EGFceZg-YB%j7TVWXRv&4#c6&AxMK$gv9~Y4C^d4avXw+2M?>j(BdQ8w! z!YR_zQ6LzGsl;jZC5LkisB&VHO0vmI9)^{`C=v}DH&1*R?qU_98PaFNl-Lo$))x#@ z#r^|rf;#}#iZC5*r68ioN%BCEPg7RDLMG~h|DV=l=!>A`hQqHK`jucVdnm2K9?vH1=eq=oY<-!8TB8U{*33NzN`#u5uW}tdrcg`5pvp zia;C_*kIYA7fjAMC7|`3l$bDYa+wJ2N+-85C=}U{*`aZb$*%)j8tscVtmx1!u9hBh zs7Vuigo~Nzi?E6c>I1R(tq*B67K6x<+X?8`wh?wzjvV>%W8N6?(GK_67YGi6?~&!L zzVj;!WdO?G>u@}#jfK$R7Ja263{o<)Ya{76RnGD7E+M!bVO6_PUhQ0!$$_0y+}@ z+E5*iBwZFFiJ#)vuLIrVwk!^fh?d~<)lQ3% zGH7-+lA2LSt3@c!HqO#>xcx=Mprj;bEiOHdhCcjr_n*Z6k&-TP_{ z52MqqgoYj?_s)DQFHt%L9fa+scH>1^4D5x<9AEqT+UHN4RM>Bh|5%dTCW8hZqVJ=w(L1=#7d_<}lH6zt(QR+dtkt2OGBScWl#X8V` zTlI_NaE2-L4_e}+0qdHP@m@)H=Y%j+h(Hcdj?ms2#1%+kYnU+oBf2>fU(-APu4@28 zOmn@4evV=At+CLo4D=0GBzGig`NPl}RjM?LXN2q++`Ql^8&Hc-*bJl2XVW#}$ASj# ziI6qKXuA46YgUt+S)^xIgHGcnD0$051Lcg5QHt%cz$mHLG9!Gxb&zihBO(#K(pp5M zzp_*7MXy$ohIQ#7VD$%&)@`wLVXX+#K7{YN?bz4wrKKrNayWYXs+>v2(^@8Y1%!%J z!==U&8kXww870E(P0hj1m~EZ=Bar&sZd6}pLd-j2P+j=?j{|kHLJF)J^tat*vtRf| zGJ{P^AkDzp2QsL1M(~2Zc6co}ACnteX~h|eSc&i*M#d$JQ7@AnTGgp?O+kf*4m74$($A#-_Ct%a8JjPqE>y z+0tM^bJVstLN0cMEE6!3+!=6g#M80qW8Mr|W?NwDG?WcfvVq#T4CEh189~4n3E32`1Zk!;M7Ye8HqjHoA_W4wKDdQ?bwym&<%C z+~$cXD7}>COv&Wga|oH@PwYxzP=um}^{TJ2jhigLzr{J2Wk*ss+b~~-xB=$|npSSB z2B=Teza&1a1?IqPj}~}9z3$5|2`L>eWhkUA&~H6u854H<%YRs+?Uzr)L!x-(1`tN7z!0M~}3aI%bC!I+m`F)u@=7wR&*ZuJOfF z2aTRmgKfqxPqnMNY8QWPQ3b^(NX-6M{4I zF45Vc>gA$thEobP`ocANnD;DNk;wFvIxRNgYv>aLH;NoP3Caa-LU#@tN+KOr*U1!^ zVai?m2I(}o=Hn6;5|v0zrV2$%DVWjdHM8vo88x@Tlh|h8OE#({@B@c#;SNVlRp&>5 z2n$6kP992I5t_w9F>a;ktDe=RbL@fwh17-Q5o=QfJ!b#%KIc^{f7#@6HKq66-?;Z+ zpWpQy$sE=Fq@R4aKNCkL0^?!ogs>o&|G45V*^|d@|Gic3T`*6z^z?iq z=z*#?b8>espD$poL{@f%c3#-#6C|I=L%eFnB7}k5MB#8pMVM)h*2T$%NBB*4#^loQ zdm-Kiu3c48RDsa|jDUqH@{a`l<)6D&F)Z>r?IyvOaCX4O!geL82QxTQWQyiIRoaKo zm}`y+8+5rJm#N%!#1MlbFfBiKCWcaVTb*2+vYfFVUzELf4aS{G9uifXm@?nb zRjaIQA9zbJo%|y1t-&xxxzO3cJsr85w?WHMaeUh232bHsj*nB^W}Fn);4s?boKzOT zuAykXu;Cpk&A^GjFP&8Nn{ksNOlFKKVy>?7Cc}p%+QFLd>G4}rM(8SSjH%!6BDezT zB_yV#MmAW$52%VgYhUi;d5*6qpwO;viY3VDUt1_^{s2afVr9xxWzpqYRkm+dW^Ryd zTPQ@JWU@QVmyl<^T8t=f%9N275Bhjr+ud2lO`^Z}=`b8Hwm=0}Ge@7|CUvYqisXXZ zJHEjvD!R;t z6%qn46*tLhAqYosHcnl^<7sv#+>V%3dv3%~%CHK1DYxuLQ!2Hs86IG!kp+(&+?g!4 z#LEB)!Lbln4z$Ve2B~3e7%-(70LY**%5IAnaOP{s{0W#m_8z%nw-&E_>jX+jUvm=B z1xc`pQE#Jj`q%3mcgON)3dR-|13@R0XFGA9M;JwmcB$@M9%H~cJ%C^44p_JVu_jo7 zBQlt}JA&3H#q{2~h{l3>1t_tveSQ#zU?VLIvMHroVRW;^V+>6;5%~qCFRH8qrJ&39 z;wwYL;f@gwT)X?<$XzWgMYsN->=mUrvT4R9+E}U#u&R!}4YPJFJ0FF|?d}JZsJ-R^ zmyTW19A$$EO06sOy$OwJdVG6$E6dixUu_B2K(ouIJ$s0EZH7vFrzm$(n~O4!R`)UR zs)%u3ddXEP>PSa{dCZ}&!5HYp<2PZTL3(eM6e`YNa+WMv2_^rJ0lT+cEd_k=~t$0cBrH=h*vD$kY0d05&`r1MlBo8 zED`cel%hO?*|XfTBXfTBIj>I{?~h#b=)dZ4*eodI9oJuqT-|)`y~gbw1l#KfhD+D8 zRf*uUt?-A{k_?2qeO349n$WfS1C73X;>=Z!1pEFLKazPi^r~mvw-)VH=qx0YIGeB( zTZ!7LhMcdt;*ig9Nv5GfKmWsbZAAgCpamFAvIa#qfCZbFU*#UIQM2-JHE7J1jZ;)8 zh+l%zb7ySxf-RJH7_-12-`@i!=zWt=BDFgEYL+akVZEbCrqJu@@f)ahZBp!fS=S}; z#mi)B*nG>{^BwV&2ZX?ZqLW(QdSmz(ii>ZDYo z4cFGHOp1x?K2|(VF~~QdotN0^!nuOQ)lY17?q0F_SQERoHp~yBx^%bRg*>tZvQ43o z`+0{PR2bzUq8H^+HQFGZVHb7VX_c2p!UaVZqam2Ee$%w-rik98!Z?3=*f!O^ZL9p& zU%C1)AB&4&@g*96#+ z5iz{(z3zv^N-lkEf>3XRSFj@l{kjxfob7mb7uxUQ^?FjKzs=U!k^+8c1R*>diGk=y zqRQcyweT3iv^-+(u~X+UuO{X7Z!l&vA|#-IPJ%yrM~aP*W{ZIzH(HYKG7}&1R_zWC znIY%wjopzKKp0!vZ`(Yt8<}`{J2Eyvnr>_U zK0Lt4ctS&m410xqS^CrsimhRJ1!!F|+NZpsIoux>$3uj9D4F7|JoEli;jcdM2L>vc zR(4JX@LqYljUiMVUmq0Zh~|!5mx$6My|R8vNV-ZT-gZ$A-n(e&q;Y%1!4#M!XY_46 z(1dDETUE4RS=IgU;ka33gg5iO1gBls;zr(^bL1M`nW+p#?n9x|&ty+&OWuz-UMX+) zm-&;O|p^6kM^{AJ~d>NzQSZrWDVAU+V}6~^QR8z5&|QwEEJ?C?JKk;wb>*@gS59|fhKDn_Sc5n^Yc&AGgt zi)#CsPGxFSX~BT>Gi}P--rFqU|7|waf6T%9GjZ#$%&mV(-13e+d4vGNN29!$SnnA4 Q`B&>CMP)^bg+6%wf2~3VO#lD@ diff --git a/web/META-INF/resources/images/social_media_sprite.png b/web/META-INF/resources/images/social_media_sprite.png deleted file mode 100755 index 562aa8df1a11a61f22a4c71cda0d3ff1f3040fcc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3375 zcmaJ^dpy(YAKwsjPcB8&j9iLshGk>LY(ppaVI-NE5xZa*aU@h)H-!`xDc!_KZfR-` z;mD;rZmHagF2XrSipB4{PIZ2N{Q7-g-{<>0&*%Ak-kcXTl=w5VcXkv6b-3|nj zHjE%sxD?l&SQ?uNr%HU_JSGQ-27&Ch^EgymB%KQlp)(>_IM~eHCKxm#6bJLOc15~! z9O>Z^&Pg$J?<6-eEh&cWl0 z!TupdarJ;YvSa8_Yq+I34QXKkMWf*sR@P{=g&7ouv_K({z>7Awu)9i(CkuM zhTB0~66~ob)O{6CnA7HYl)4H|`K<3~mUug_hEtm{eM{|yX|iA4x%BQ0qV*=H!49PO zx<|5k;P}-a@ZevK#D9nwHmI?C#u*zS40$=lg3DH@wNAP9W{brLjSHI!_1_zb18i*R zle3Mp0WTw;WSVFAX@A828klEkFlhE_vO$4Sm5}OS<74Cg38mZ}cXp{t&Wu5*Cr-6* z*MzSYI&O-B=$xrH(}}HyYieaQE*ET3Y|8d|Qq?TpsdWA2X*8(&Fa77~hBgP9SHR%u z`BMIT{;ct+&BwqRsqVTfvnr!rRK%!<&g&QCw%+6qiG@!(z2%IlBhBfq(o(ty?_rWY z67z5`gGA>uDxxnfg&pm-&oY9n*Q}pZ8eP+{PVY@v3awa$94kCn-{Bw%6Rppr+4S>H z$u3lI%;SQYnF9|eMJ`WMryTcn>~-(PnHz8od)m%9B@eW>l`rX+E_A0(+)&?OGJGzTU0^x>rVUI_pswGxN6&WMh|@U1g-Vgu z?g0zesHl~r+^XYkg$oyEQ%(fMO^DGwZ6d*AFDm@w=dtFD6q^|_YQpl6k=0mMA>mo$ zNZn1wh5-4JrzSyr6nLsh(Q9nam+Q8Z{<;Sj-`hSGm~2Pi3d_2izcpFZ+iHtnm}pZ1 zZ#PU%$DQV*<%cdl*!bH=%`bc1p^TEkcZ8d;neo~}5{5f=?RCq%s9jXat)O+chs_O{ zh|cG~T0f{#ZC?cG8#Zsm*k4~f#Sb^*2{*2(Sz)Lsb)G;!O@BicTu9bqjpyjv?IEA+ zIG@UDPVCY{&{2eRnu8(H|6^Spa@x7B2uDhqD+z)(>m*S2rA!LIe*2i(ou zsH#0?YD4(N!K;kF(>n#^v%!JVzw~sK@vxe$OzAf)+z`Yuv z;tp>!P2IjNf|4Ry*0U5oDat@FJA5%_?s&&?=iaT}xXt59p~sJw9g2SZ8gBJqGzGy? z^_p&28(BRxu`xB;Elm(3NLF9h2%c0$-ziSFKQ ziv#(j`Vz)l0n9k*fRak+hr)=$K)0hKOI}97enMGCyYvOtRg$kq#$Qu^=E1~AZz;#+ zb->K_T}_YfQz+>5dE3&jW`*A|WVMXTKL1CQH^k&tXLfmD>!g(0$l3On4afE3en}$9 z73ACcZfQ8&vYKK7j4-BB*>WYPIVaCqgCX%yf8lx50;!VOnCSgjiV_iZO*v6;qO6ZP}*!O{UaMau6l3y-l31QA{HrF~W-b|-gO zqCnb80~e4c4;X?^zpk6quPM=Qs<&0x)@<)wtI$_6(02Roz|o9-=}&4_Yh!atJWtC^ z2S1*9J~qNlnLYWKT6* zJm>jJ=d5DJ%thn5#=}SSW1i;CAg)G_QjnK(Ud=hvS6Y3dXbyN}U!&H!30n>H>*4sK zhsfPIOXmi6+#Yp%8sKkAdcCR&C$t)MQk~GWdE8a7?+9UlYADDc`8loaWt(_(l!}ML zh>dBJW+z+b)=%9HdUPxMP4DPCFecGiQNi|HgTGpHmh?jSTYg8NmJL+yUDCt+DfM<8 zDXuT2O}H+V9PvOt6Siw=@gTmKRO)dp+f+lr8kKp;?wHc9CmXlA=_spEt}l2}RRyJ) zow={TO|I_aZ**tP&I^+5j&;@WWyaGBThJF*aC#%`IOrQNRrWmYTB4rHdy z-!J2XgevuN+S*-l`C27&J1nZ~G{A&zof;qMNDNEOeqs~47*lh`CwdpOHh3fijdM7{zsS6CfYDkf^xfDevK*oa)%2NVN$suJ#&>cvT7WgRG zTxy-_*OStNz*Y`$+^+@R2?5M6>0D{d*CV3?fJp^78iVbZeHS|4K8M@x_aSOa)aJsV zi^{DO*rAYoL=-}tpQ?KGeG+6vL)hFT_m}W9ap<;>*7MBR&xI{R^@R%?ymo2@$Ox!C zu>GGUh?3j@YTdSKNU%b<+Wlb32=$Wbxp+7KA#DF)BdT7>QzB?j?X|TFatx1Mif_WM zm`Fhoqs*ote?vutM}pF!8W^=9Av?YlB{6wfmBw&*a2AMoT>}~Du5p7e5b2&L^nb?KKQ_Y0EGddL;wH) diff --git a/web/META-INF/resources/index.html b/web/META-INF/resources/index.html index 8857283..9ee619a 100755 --- a/web/META-INF/resources/index.html +++ b/web/META-INF/resources/index.html @@ -1,4 +1,4 @@ - + - - - MUDROD - - - - - - - - - - - - - - - - - + + + MUDROD + + + + + + + - - - + + + + + + + + + + + - - - -
+ + -
-
- - + +
+ +
+
+ + \ No newline at end of file diff --git a/web/META-INF/resources/js/app.js b/web/META-INF/resources/js/app.js index 6b0473e..4b4cab1 100755 --- a/web/META-INF/resources/js/app.js +++ b/web/META-INF/resources/js/app.js @@ -17,32 +17,28 @@ /* App Module */ var mudrod = angular.module('mudrodApp', [ - 'ngRoute', + 'ngRoute', 'mudrodControllers', - 'mudrodServices' + 'mudrodServices' ]); mudrod.config(['$routeProvider', '$locationProvider', - function($routeProvider, $locationProvider) { - $routeProvider. - when('/', { - templateUrl: 'partials/search.html' - //controller: 'searchCtrl' - }).when('/metadataView/:query', { - templateUrl: 'partials/metadataResults.html', - controller: 'metadataViewCtrl' - }).when('/metadataView/:query/:opt/', { - templateUrl: 'partials/metadataResults.html' - //controller: 'metadataViewCtrl', - //controllerAs: 'vm' - }).when('/datasetView/:shortname/', { - templateUrl: 'partials/datasetResults.html', - controller: 'datasetViewCtrl' - }).when('/datasetView/:shortname/:query/:opt/', { - templateUrl: 'partials/datasetResults.html', - controller: 'datasetViewCtrl' - });; + function ($routeProvider, $locationProvider) { + $routeProvider.when('/', { + templateUrl: 'partials/search.html' + }).when('/metadataView/:query', { + templateUrl: 'partials/metadataResults.html', + controller: 'metadataViewCtrl' + }).when('/metadataView/:query/:opt/', { + templateUrl: 'partials/metadataResults.html' + }).when('/datasetView/:shortname/', { + templateUrl: 'partials/datasetResults.html', + controller: 'datasetViewCtrl' + }).when('/datasetView/:shortname/:query/:opt/', { + templateUrl: 'partials/datasetResults.html', + controller: 'datasetViewCtrl' + }); $locationProvider.html5Mode(false).hashPrefix('!'); }]); \ No newline at end of file diff --git a/web/META-INF/resources/js/controllers.js b/web/META-INF/resources/js/controllers.js index 8e04fb7..d0d7112 100755 --- a/web/META-INF/resources/js/controllers.js +++ b/web/META-INF/resources/js/controllers.js @@ -28,7 +28,6 @@ mudrodControllers.controller('searchCtrl', ['$scope', '$rootScope', '$location', Autocomplete.get({term: string}, function success(response) { $scope.filterSearch = response; - }, function error(errorResponse) { console.log("Error:" + JSON.stringify(errorResponse)); diff --git a/web/META-INF/resources/partials/datasetResults.html b/web/META-INF/resources/partials/datasetResults.html index a07c9a0..549ca62 100644 --- a/web/META-INF/resources/partials/datasetResults.html +++ b/web/META-INF/resources/partials/datasetResults.html @@ -103,7 +103,7 @@

-
+

Related Datasets @@ -117,7 +117,7 @@

-
+

Related Keyword Searches diff --git a/web/META-INF/resources/partials/footer.html b/web/META-INF/resources/partials/footer.html new file mode 100644 index 0000000..13d526b --- /dev/null +++ b/web/META-INF/resources/partials/footer.html @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/web/META-INF/resources/partials/main-header.html b/web/META-INF/resources/partials/main-header.html new file mode 100644 index 0000000..6db05dc --- /dev/null +++ b/web/META-INF/resources/partials/main-header.html @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/web/META-INF/resources/partials/metadataResults.html b/web/META-INF/resources/partials/metadataResults.html index 8d1b86d..c678a19 100755 --- a/web/META-INF/resources/partials/metadataResults.html +++ b/web/META-INF/resources/partials/metadataResults.html @@ -11,27 +11,27 @@ express or implied. See the License for the specific language governing permissions and limitations under the License. --> -
+
-
+
+

{{vm.totalMatches}} matches -

@@ -45,33 +45,33 @@

  • {{page}} -
  • +
  • Next
  • Last
  • - -
    + +

    @@ -95,32 +95,33 @@

  • {{page}} -
  • +
  • Next
  • Last
  • - +

    -
    +
    - \ No newline at end of file diff --git a/web/META-INF/resources/partials/navbar-search.html b/web/META-INF/resources/partials/navbar-search.html index f03f9a3..d654af4 100755 --- a/web/META-INF/resources/partials/navbar-search.html +++ b/web/META-INF/resources/partials/navbar-search.html @@ -30,7 +30,7 @@ - -
    \ No newline at end of file From 1e1b66459b1730d1064b2ef755e90da9cb996bee Mon Sep 17 00:00:00 2001 From: Frank Greguska Date: Tue, 13 Jun 2017 17:49:27 -0700 Subject: [PATCH 29/33] autocomplete needs to be black --- web/META-INF/resources/css/index.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web/META-INF/resources/css/index.css b/web/META-INF/resources/css/index.css index 8783134..f04c2f8 100644 --- a/web/META-INF/resources/css/index.css +++ b/web/META-INF/resources/css/index.css @@ -115,6 +115,7 @@ a:link, a:visited { .autocomplete { overflow-y: auto; height: 15em; + color: black; } .toolbar .form { From 48f387e571c60fbf6cb14b68e164e4794e54bf0a Mon Sep 17 00:00:00 2001 From: Frank Greguska Date: Tue, 13 Jun 2017 18:07:52 -0700 Subject: [PATCH 30/33] fixed bug where controller was being called twice --- web/META-INF/resources/js/controllers.js | 4 ++-- web/META-INF/resources/partials/metadataResults.html | 2 +- web/META-INF/resources/partials/search-results.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/META-INF/resources/js/controllers.js b/web/META-INF/resources/js/controllers.js index 576e3a2..df6a394 100755 --- a/web/META-INF/resources/js/controllers.js +++ b/web/META-INF/resources/js/controllers.js @@ -184,8 +184,8 @@ mudrodControllers.controller('metadataViewCtrl', ['$rootScope', '$scope', '$rout vm.totalMatches = vm.PDItems.length; vm.query = word; vm.opt = opt; - $scope.searchComplete = true; initController(); + $scope.searchComplete = true; }, function error(errorResponse) { $scope.searchComplete = true; @@ -201,8 +201,8 @@ mudrodControllers.controller('metadataViewCtrl', ['$rootScope', '$scope', '$rout vm.totalMatches = vm.PDItems.length; vm.query = word; vm.opt = opt; - $scope.searchComplete = true; initController(); + $scope.searchComplete = true; }, function error(errorResponse) { $scope.searchComplete = true; diff --git a/web/META-INF/resources/partials/metadataResults.html b/web/META-INF/resources/partials/metadataResults.html index 89c7a08..fbdc9e7 100755 --- a/web/META-INF/resources/partials/metadataResults.html +++ b/web/META-INF/resources/partials/metadataResults.html @@ -13,7 +13,7 @@ -->
    -
    +
    diff --git a/web/META-INF/resources/partials/search-results.html b/web/META-INF/resources/partials/search-results.html index 1beb537..b47a92e 100644 --- a/web/META-INF/resources/partials/search-results.html +++ b/web/META-INF/resources/partials/search-results.html @@ -1,4 +1,4 @@ -
    +
    +