- * Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The
- * getSupportedExtensions function would return a set with a single element "jar".
+ * Returns the {@link java.io.FileFilter} used to determine which files are to be analyzed. An example would be an analyzer
+ * that inspected Java jar files. Implementors may use {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.
*
+ * @return the file filter used to determine which files are to be analyzed
+ *
*
- * Note: when implementing this the extensions returned MUST be lowercase.
- *
- * @return The file extensions supported by this analyzer.
- *
- *
- * If the analyzer returns null it will not cause additional files to be analyzed but will be executed against every
- * file loaded
+ * If the analyzer returns null it will not cause additional files to be analyzed, but will be executed against every file
+ * loaded.
*/
- protected abstract Set getSupportedExtensions();
+ protected abstract FileFilter getFileFilter();
/**
* Initializes the file type analyzer.
@@ -122,8 +121,8 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
protected abstract void initializeFileTypeAnalyzer() throws Exception;
/**
- * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
- * scanned, and added to the list of dependencies within the engine.
+ * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
+ * and added to the list of dependencies within the engine.
*
* @param dependency the dependency to analyze
* @param engine the engine scanning
@@ -171,8 +170,8 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
}
/**
- * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
- * scanned, and added to the list of dependencies within the engine.
+ * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
+ * and added to the list of dependencies within the engine.
*
* @param dependency the dependency to analyze
* @param engine the engine scanning
@@ -185,38 +184,28 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
}
}
- /**
- * Returns whether or not this analyzer can process the given extension.
- *
- * @param extension the file extension to test for support.
- * @return whether or not the specified file extension is supported by this analyzer.
- */
@Override
- public final boolean supportsExtension(String extension) {
- if (!enabled) {
- return false;
- }
- final Set ext = getSupportedExtensions();
- if (ext == null) {
- LOGGER.error("The '{}' analyzer is misconfigured and does not have any file extensions;"
- + " it will be disabled", getName());
- return false;
- } else {
- final boolean match = ext.contains(extension);
- if (match) {
- filesMatched = match;
+ public boolean accept(File pathname) {
+ final FileFilter filter = getFileFilter();
+ boolean accepted = false;
+ if (null == filter) {
+ LOGGER.error("The '{}' analyzer is misconfigured and does not have a file filter; it will be disabled", getName());
+ } else if (enabled) {
+ accepted = filter.accept(pathname);
+ if (accepted) {
+ filesMatched = true;
}
- return match;
}
+ return accepted;
}
-//
+ //
//
/**
*
- * Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a
- * final static declaration.
- *
+ * Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a final static
+ * declaration.
+ *
*
* This implementation was copied from
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction
- * An analyzer that extracts files from archives and ensures any supported files contained within the archive are added
- * to the dependency list.
+ * An analyzer that extracts files from archives and ensures any supported files contained within the archive are added to the
+ * dependency list.
*
* @author Jeremy Long
*/
@@ -97,8 +100,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
*/
private static final Set ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
/**
- * The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need
- * to be explicitly handled in extractFiles().
+ * The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need to be
+ * explicitly handled in extractFiles().
*/
private static final Set EXTENSIONS = newHashSet("tar", "gz", "tgz");
@@ -116,14 +119,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
EXTENSIONS.addAll(ZIPPABLES);
}
- /**
- * Returns a list of file EXTENSIONS supported by this analyzer.
- *
- * @return a list of file EXTENSIONS supported by this analyzer.
- */
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
+
@Override
- public Set getSupportedExtensions() {
- return EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
@@ -193,8 +193,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
- * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
- * scanned, and added to the list of dependencies within the engine.
+ * Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
+ * and added to the list of dependencies within the engine.
*
* @param dependency the dependency to analyze
* @param engine the engine scanning
@@ -229,14 +229,14 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
//TODO - can we get more evidence from the parent? EAR contains module name, etc.
//analyze the dependency (i.e. extract files) if it is a supported type.
- if (this.supportsExtension(d.getFileExtension()) && scanDepth < MAX_SCAN_DEPTH) {
+ if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) {
scanDepth += 1;
analyze(d, engine);
scanDepth -= 1;
}
}
}
- if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
+ if (REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) {
final File tdir = getNextTempDirectory();
final String fileName = dependency.getFileName();
@@ -320,9 +320,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
- final String uncompressedExt = FileUtils.getFileExtension(uncompressedName).toLowerCase();
- if (engine.supportsExtension(uncompressedExt)) {
- decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), new File(destination, uncompressedName));
+ File f = new File(destination, uncompressedName);
+ if (engine.accept(f)) {
+ decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), f);
}
}
} catch (ArchiveExtractionException ex) {
@@ -362,8 +362,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
}
} else {
final File file = new File(destination, entry.getName());
- final String ext = FileUtils.getFileExtension(file.getName());
- if (engine.supportsExtension(ext)) {
+ if (engine.accept(file)) {
LOGGER.debug("Extracting '{}'", file.getPath());
BufferedOutputStream bos = null;
FileOutputStream fos = null;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java
index f8eade81e..fff5e53ae 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java
@@ -17,36 +17,37 @@
*/
package org.owasp.dependencycheck.analyzer;
+import ch.qos.cal10n.IMessageConveyor;
+import ch.qos.cal10n.MessageConveyor;
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-
-import ch.qos.cal10n.IMessageConveyor;
-import ch.qos.cal10n.MessageConveyor;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.utils.DCResources;
+import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.cal10n.LocLogger;
import org.slf4j.cal10n.LocLoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
/**
* Analyzer for getting company, product, and version information from a .NET assembly.
*
@@ -66,7 +67,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The list of supported extensions
*/
- private static final Set SUPPORTED_EXTENSIONS = newHashSet("dll", "exe");
+ private static final String[] SUPPORTED_EXTENSIONS = {"dll", "exe"};
/**
* The temp value for GrokAssembly.exe
*/
@@ -78,15 +79,15 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
/**
* Message Conveyer
*/
- private final IMessageConveyor MESSAGE_CONVERYOR = new MessageConveyor(Locale.getDefault());
+ private static final IMessageConveyor MESSAGE_CONVERYOR = new MessageConveyor(Locale.getDefault());
/**
* LocLoggerFactory for localized logger
*/
- private final LocLoggerFactory LLFACTORY = new LocLoggerFactory(MESSAGE_CONVERYOR);
+ private static final LocLoggerFactory LLFACTORY = new LocLoggerFactory(MESSAGE_CONVERYOR);
/**
* Logger
*/
- private final LocLogger LOGGER = LLFACTORY.getLocLogger(AssemblyAnalyzer.class);
+ private static final LocLogger LOGGER = LLFACTORY.getLocLogger(AssemblyAnalyzer.class);
/**
* Builds the beginnings of a List for ProcessBuilder
@@ -284,6 +285,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
}
+ /**
+ * Removes resources used from the local file system.
+ *
+ * @throws Exception thrown if there is a problem closing the analyzer
+ */
@Override
public void close() throws Exception {
super.close();
@@ -296,14 +302,12 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
}
}
- /**
- * Gets the set of extensions supported by this analyzer.
- *
- * @return the list of supported extensions
- */
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
+ SUPPORTED_EXTENSIONS).build();
+
@Override
- public Set getSupportedExtensions() {
- return SUPPORTED_EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java
index 1e81a0df6..d25ad57de 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java
@@ -17,23 +17,24 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.EvidenceCollection;
+import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.UrlStringUtils;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* Used to analyze Autoconf input files named configure.ac or configure.in. Files simply named "configure" are also analyzed,
* assuming they are generated by Autoconf, and contain certain special package descriptor variables.
@@ -71,8 +72,7 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The set of file extensions supported by this analyzer.
*/
- private static final Set EXTENSIONS = newHashSet("ac", "in",
- CONFIGURE);
+ private static final String[] EXTENSIONS = {"ac", "in"};
/**
* Matches AC_INIT variables in the output configure script.
@@ -104,13 +104,19 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
- * Returns a list of file EXTENSIONS supported by this analyzer.
+ * The file filter used to determine which files this analyzer supports.
+ */
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFilenames(CONFIGURE).addExtensions(
+ EXTENSIONS).build();
+
+ /**
+ * Returns the FileFilter
*
- * @return a list of file EXTENSIONS supported by this analyzer.
+ * @return the FileFilter
*/
@Override
- public Set getSupportedExtensions() {
- return EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
@@ -128,6 +134,7 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
*
* @return the phase that the analyzer is intended to run in.
*/
+ @Override
public AnalysisPhase getAnalysisPhase() {
return ANALYSIS_PHASE;
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java
index 4d0470f8e..8b004765e 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java
@@ -511,8 +511,8 @@ public class CPEAnalyzer implements Analyzer {
}
for (VulnerableSoftware vs : cpes) {
DependencyVersion dbVer;
- if (vs.getRevision() != null && !vs.getRevision().isEmpty()) {
- dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getRevision());
+ if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) {
+ dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getUpdate());
} else {
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java
index 94074deb7..70e8d3159 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java
@@ -17,12 +17,6 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.URL;
-import java.util.List;
-import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
@@ -32,13 +26,21 @@ import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.xml.pom.PomUtils;
-import org.owasp.dependencycheck.utils.DownloadFailedException;
-import org.owasp.dependencycheck.utils.Downloader;
-import org.owasp.dependencycheck.utils.InvalidSettingException;
-import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+import org.owasp.dependencycheck.utils.DownloadFailedException;
+import org.owasp.dependencycheck.utils.Downloader;
+import org.owasp.dependencycheck.utils.FileFilterBuilder;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
+import org.owasp.dependencycheck.utils.Settings;
+
/**
* Analyzer which will attempt to locate a dependency, and the GAV information, by querying Central for the dependency's SHA-1
* digest.
@@ -65,7 +67,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The types of files on which this will work.
*/
- private static final Set SUPPORTED_EXTENSIONS = newHashSet("jar");
+ private static final String SUPPORTED_EXTENSIONS = "jar";
/**
* The analyzer should be disabled if there are errors, so this is a flag to determine if such an error has occurred.
@@ -164,13 +166,13 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
- * Returns the extensions for which this Analyzer runs.
- *
- * @return the extensions for which this Analyzer runs
+ * The file filter used to determine which files this analyzer supports.
*/
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
+
@Override
- public Set getSupportedExtensions() {
- return SUPPORTED_EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
@@ -206,7 +208,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
pomFile = File.createTempFile("pom", ".xml", baseDir);
if (!pomFile.delete()) {
LOGGER.warn("Unable to fetch pom.xml for {} from Central; "
- + "this could result in undetected CPE/CVEs.", dependency.getFileName());
+ + "this could result in undetected CPE/CVEs.", dependency.getFileName());
LOGGER.debug("Unable to delete temp file");
}
LOGGER.debug("Downloading {}", ma.getPomUrl());
@@ -215,7 +217,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
} catch (DownloadFailedException ex) {
LOGGER.warn("Unable to download pom.xml for {} from Central; "
- + "this could result in undetected CPE/CVEs.", dependency.getFileName());
+ + "this could result in undetected CPE/CVEs.", dependency.getFileName());
} finally {
if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
pomFile.deleteOnExit();
@@ -233,5 +235,4 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
errorFlag = true;
}
}
-
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileTypeAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileTypeAnalyzer.java
index 0151578c6..bb7467a4c 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileTypeAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileTypeAnalyzer.java
@@ -17,20 +17,14 @@
*/
package org.owasp.dependencycheck.analyzer;
+import java.io.FileFilter;
+
/**
* An Analyzer that scans specific file types.
*
* @author Jeremy Long
*/
-public interface FileTypeAnalyzer extends Analyzer {
-
- /**
- * Returns whether or not this analyzer can process the given extension.
- *
- * @param extension the file extension to test for support.
- * @return whether or not the specified file extension is supported by this analyzer.
- */
- boolean supportsExtension(String extension);
+public interface FileTypeAnalyzer extends Analyzer, FileFilter {
/**
* Resets the analyzers state.
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java
index f9c180446..4c1c80145 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java
@@ -17,14 +17,7 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.Reader;
+import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -47,6 +40,7 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.EvidenceCollection;
+import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.xml.pom.License;
import org.owasp.dependencycheck.xml.pom.PomUtils;
import org.owasp.dependencycheck.xml.pom.Model;
@@ -168,16 +162,21 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The set of file extensions supported by this analyzer.
*/
- private static final Set EXTENSIONS = newHashSet("jar", "war");
+ private static final String[] EXTENSIONS = {"jar", "war"};
/**
- * Returns a list of file EXTENSIONS supported by this analyzer.
+ * The file filter used to determine which files this analyzer supports.
+ */
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
+
+ /**
+ * Returns the FileFilter.
*
- * @return a list of file EXTENSIONS supported by this analyzer.
+ * @return the FileFilter
*/
@Override
- public Set getSupportedExtensions() {
- return EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
@@ -388,7 +387,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
* @param dependency the dependency being analyzed
* @return returns the POM object
* @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
- * {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
+ * {@link org.owasp.dependencycheck.xml.pom.Model} object
*/
private Model extractPom(String path, JarFile jar, Dependency dependency) throws AnalysisException {
InputStream input = null;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java
deleted file mode 100644
index 077a6d667..000000000
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzer.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * This file is part of dependency-check-core.
- *
- * 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.
- *
- * Copyright (c) 2014 Jeremy Long. All Rights Reserved.
- */
-package org.owasp.dependencycheck.analyzer;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.Set;
-import java.util.regex.Pattern;
-import org.owasp.dependencycheck.Engine;
-import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
-import org.owasp.dependencycheck.dependency.Dependency;
-import org.owasp.dependencycheck.utils.Settings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- *
- * Used to analyze a JavaScript file to gather information to aid in identification of a CPE identifier.
- *
- * @author Jeremy Long
- */
-public class JavaScriptAnalyzer extends AbstractFileTypeAnalyzer {
-
- /**
- * The logger.
- */
- private static final Logger LOGGER = LoggerFactory.getLogger(JavaScriptAnalyzer.class);
-
- //
- /**
- * The name of the analyzer.
- */
- private static final String ANALYZER_NAME = "JavaScript Analyzer";
- /**
- * The phase that this analyzer is intended to run in.
- */
- private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
- /**
- * The set of file extensions supported by this analyzer.
- */
- private static final Set EXTENSIONS = newHashSet("js");
-
- /**
- * Returns a list of file EXTENSIONS supported by this analyzer.
- *
- * @return a list of file EXTENSIONS supported by this analyzer.
- */
- @Override
- public Set getSupportedExtensions() {
- return EXTENSIONS;
- }
-
- /**
- * Returns the name of the analyzer.
- *
- * @return the name of the analyzer.
- */
- @Override
- public String getName() {
- return ANALYZER_NAME;
- }
-
- /**
- * Returns the phase that the analyzer is intended to run in.
- *
- * @return the phase that the analyzer is intended to run in.
- */
- @Override
- public AnalysisPhase getAnalysisPhase() {
- return ANALYSIS_PHASE;
- }
- //
- /**
- * Returns the key used in the properties file to reference the analyzer's enabled property.
- *
- * @return the analyzer's enabled property setting key
- */
- @Override
- protected String getAnalyzerEnabledSettingKey() {
- return Settings.KEYS.ANALYZER_JAVASCRIPT_ENABLED;
- }
-
- /**
- * Loads a specified JavaScript file and collects information from the copyright information contained within.
- *
- * @param dependency the dependency to analyze.
- * @param engine the engine that is scanning the dependencies
- * @throws AnalysisException is thrown if there is an error reading the JavaScript file.
- */
- @Override
- public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
- BufferedReader fin = null;
- try {
- // /\*([^\*][^/]|[\r\n\f])+?\*/
- final Pattern extractComments = Pattern.compile("(/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/)|(//.*)", Pattern.MULTILINE);
- File file = dependency.getActualFile();
- fin = new BufferedReader(new FileReader(file));
- StringBuilder sb = new StringBuilder(2000);
- String text;
- while ((text = fin.readLine()) != null) {
- sb.append(text);
- }
- } catch (FileNotFoundException ex) {
- final String msg = String.format("Dependency file not found: '%s'", dependency.getActualFilePath());
- throw new AnalysisException(msg, ex);
- } catch (IOException ex) {
- LOGGER.error("", ex);
- } finally {
- if (fin != null) {
- try {
- fin.close();
- } catch (IOException ex) {
- LOGGER.trace("", ex);
- }
- }
- }
- }
-
- @Override
- protected void initializeFileTypeAnalyzer() throws Exception {
-
- }
-}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java
index 101163745..226c0aff2 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java
@@ -17,12 +17,6 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
@@ -32,13 +26,21 @@ import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
import org.owasp.dependencycheck.xml.pom.PomUtils;
-import org.owasp.dependencycheck.utils.InvalidSettingException;
-import org.owasp.dependencycheck.utils.DownloadFailedException;
-import org.owasp.dependencycheck.utils.Downloader;
-import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.owasp.dependencycheck.utils.DownloadFailedException;
+import org.owasp.dependencycheck.utils.Downloader;
+import org.owasp.dependencycheck.utils.FileFilterBuilder;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
+import org.owasp.dependencycheck.utils.Settings;
+
/**
* Analyzer which will attempt to locate a dependency on a Nexus service by SHA-1 digest of the dependency.
*
@@ -78,7 +80,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The types of files on which this will work.
*/
- private static final Set SUPPORTED_EXTENSIONS = newHashSet("jar");
+ private static final String SUPPORTED_EXTENSIONS = "jar";
/**
* The Nexus Search to be set up for this analyzer.
@@ -184,13 +186,18 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
- * Returns the extensions for which this Analyzer runs.
+ * The file filter used to determine which files this analyzer supports.
+ */
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
+
+ /**
+ * Returns the FileFilter
*
- * @return the extensions for which this Analyzer runs
+ * @return the FileFilter
*/
@Override
- public Set getSupportedExtensions() {
- return SUPPORTED_EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
@@ -223,7 +230,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
pomFile = File.createTempFile("pom", ".xml", baseDir);
if (!pomFile.delete()) {
LOGGER.warn("Unable to fetch pom.xml for {} from Nexus repository; "
- + "this could result in undetected CPE/CVEs.", dependency.getFileName());
+ + "this could result in undetected CPE/CVEs.", dependency.getFileName());
LOGGER.debug("Unable to delete temp file");
}
LOGGER.debug("Downloading {}", ma.getPomUrl());
@@ -231,7 +238,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
PomUtils.analyzePOM(dependency, pomFile);
} catch (DownloadFailedException ex) {
LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; "
- + "this could result in undetected CPE/CVEs.", dependency.getFileName());
+ + "this could result in undetected CPE/CVEs.", dependency.getFileName());
} finally {
if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
pomFile.deleteOnExit();
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java
index 237b349ae..9e24f56f5 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java
@@ -17,10 +17,6 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Set;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.data.nuget.NugetPackage;
@@ -29,10 +25,16 @@ import org.owasp.dependencycheck.data.nuget.NuspecParser;
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
+import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
/**
* Analyzer which will parse a Nuspec file to gather module information.
*
@@ -58,7 +60,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The types of files on which this will work.
*/
- private static final Set SUPPORTED_EXTENSIONS = newHashSet("nuspec");
+ private static final String SUPPORTED_EXTENSIONS = "nuspec";
/**
* Initializes the analyzer once before any analysis is performed.
@@ -100,13 +102,19 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
- * Returns the extensions for which this Analyzer runs.
+ * The file filter used to determine which files this analyzer supports.
+ */
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
+ SUPPORTED_EXTENSIONS).build();
+
+ /**
+ * Returns the FileFilter
*
- * @return the extensions for which this Analyzer runs
+ * @return the FileFilter
*/
@Override
- public Set getSupportedExtensions() {
- return SUPPORTED_EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java
index 6b31c6973..87d21f168 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzer.java
@@ -17,17 +17,6 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FilenameFilter;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.InternetHeaders;
-
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.input.AutoCloseInputStream;
@@ -37,13 +26,19 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.EvidenceCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetHeaders;
+import java.io.*;
+import java.util.regex.Pattern;
import org.owasp.dependencycheck.utils.ExtractionException;
import org.owasp.dependencycheck.utils.ExtractionUtil;
+import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.FileUtils;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.UrlStringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Used to analyze a Wheel or egg distribution files, or their contents in unzipped form, and collect information that can be used
@@ -86,11 +81,10 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
/**
* The set of file extensions supported by this analyzer.
*/
- private static final Set EXTENSIONS = newHashSet("whl", "egg",
- "zip", METADATA, PKG_INFO);
+ private static final String[] EXTENSIONS = {"whl", "egg", "zip"};
/**
- * Used to match on egg archive candidate extenssions.
+ * Used to match on egg archive candidate extensions.
*/
private static final Pattern EGG_OR_ZIP = Pattern.compile("egg|zip");
@@ -114,23 +108,29 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
/**
* Filter that detects files named "METADATA".
*/
- private static final FilenameFilter METADATA_FILTER = new NameFileFilter(
+ private static final NameFileFilter METADATA_FILTER = new NameFileFilter(
METADATA);
/**
* Filter that detects files named "PKG-INFO".
*/
- private static final FilenameFilter PKG_INFO_FILTER = new NameFileFilter(
+ private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter(
PKG_INFO);
/**
- * Returns a list of file EXTENSIONS supported by this analyzer.
+ * The file filter used to determine which files this analyzer supports.
+ */
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFileFilters(
+ METADATA_FILTER, PKG_INFO_FILTER).addExtensions(EXTENSIONS).build();
+
+ /**
+ * Returns the FileFilter
*
- * @return a list of file EXTENSIONS supported by this analyzer.
+ * @return the FileFilter
*/
@Override
- public Set getSupportedExtensions() {
- return EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java
index a2080792f..8f909614b 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java
@@ -17,17 +17,6 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
@@ -36,11 +25,21 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.EvidenceCollection;
+import org.owasp.dependencycheck.utils.FileFilterBuilder;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.UrlStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* Used to analyze a Python package, and collect information that can be used to determine the associated CPE.
*
@@ -63,8 +62,7 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
/**
* Filename extensions for files to be analyzed.
*/
- private static final Set EXTENSIONS = Collections
- .unmodifiableSet(Collections.singleton("py"));
+ private static final String EXTENSIONS = "py";
/**
* Pattern for matching the module docstring in a source file.
@@ -135,13 +133,18 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
}
/**
- * Returns the set of supported file extensions.
+ * The file filter used to determine which files this analyzer supports.
+ */
+ private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
+
+ /**
+ * Returns the FileFilter
*
- * @return the set of supported file extensions
+ * @return the FileFilter
*/
@Override
- protected Set getSupportedExtensions() {
- return EXTENSIONS;
+ protected FileFilter getFileFilter() {
+ return FILTER;
}
/**
@@ -209,12 +212,12 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
*/
private boolean analyzeFileContents(Dependency dependency, File file)
throws AnalysisException {
- String contents = "";
+ String contents;
try {
contents = FileUtils.readFileToString(file).trim();
} catch (IOException e) {
throw new AnalysisException(
- "Problem occured while reading dependency file.", e);
+ "Problem occurred while reading dependency file.", e);
}
boolean found = false;
if (!contents.isEmpty()) {
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java
index a2c05f2b2..d787885f1 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/ConnectionFactory.java
@@ -35,9 +35,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Loads the configured database driver and returns the database connection. If the embedded H2 database is used
- * obtaining a connection will ensure the database file exists and that the appropriate table structure has been
- * created.
+ * Loads the configured database driver and returns the database connection. If the embedded H2 database is used obtaining a
+ * connection will ensure the database file exists and that the appropriate table structure has been created.
*
* @author Jeremy Long
*/
@@ -55,6 +54,10 @@ public final class ConnectionFactory {
* Resource location for SQL file used to create the database schema.
*/
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
+ /**
+ * Resource location for SQL file used to create the database schema.
+ */
+ public static final String DB_STRUCTURE_UPDATE_RESOURCE = "data/upgrade_%s.sql";
/**
* The database driver used to connect to the database.
*/
@@ -79,8 +82,8 @@ public final class ConnectionFactory {
}
/**
- * Initializes the connection factory. Ensuring that the appropriate drivers are loaded and that a connection can be
- * made successfully.
+ * Initializes the connection factory. Ensuring that the appropriate drivers are loaded and that a connection can be made
+ * successfully.
*
* @throws DatabaseException thrown if we are unable to connect to the database
*/
@@ -114,8 +117,7 @@ public final class ConnectionFactory {
try {
connectionString = Settings.getConnectionString(
Settings.KEYS.DB_CONNECTION_STRING,
- Settings.KEYS.DB_FILE_NAME,
- Settings.KEYS.DB_VERSION);
+ Settings.KEYS.DB_FILE_NAME);
} catch (IOException ex) {
LOGGER.debug(
"Unable to retrieve the database connection string", ex);
@@ -162,13 +164,12 @@ public final class ConnectionFactory {
LOGGER.debug("", dex);
throw new DatabaseException("Unable to create the database structure");
}
- } else {
- try {
- ensureSchemaVersion(conn);
- } catch (DatabaseException dex) {
- LOGGER.debug("", dex);
- throw new DatabaseException("Database schema does not match this version of dependency-check");
- }
+ }
+ try {
+ ensureSchemaVersion(conn);
+ } catch (DatabaseException dex) {
+ LOGGER.debug("", dex);
+ throw new DatabaseException("Database schema does not match this version of dependency-check", dex);
}
} finally {
if (conn != null) {
@@ -183,8 +184,8 @@ public final class ConnectionFactory {
/**
* Cleans up resources and unloads any registered database drivers. This needs to be called to ensure the driver is
- * unregistered prior to the finalize method being called as during shutdown the class loader used to load the
- * driver may be unloaded prior to the driver being de-registered.
+ * unregistered prior to the finalize method being called as during shutdown the class loader used to load the driver may be
+ * unloaded prior to the driver being de-registered.
*/
public static synchronized void cleanup() {
if (driver != null) {
@@ -229,8 +230,7 @@ public final class ConnectionFactory {
*/
private static boolean h2DataFileExists() throws IOException {
final File dir = Settings.getDataDirectory();
- final String name = Settings.getString(Settings.KEYS.DB_FILE_NAME);
- final String fileName = String.format(name, DB_SCHEMA_VERSION);
+ final String fileName = Settings.getString(Settings.KEYS.DB_FILE_NAME);
final File file = new File(dir, fileName);
return file.exists();
}
@@ -278,6 +278,55 @@ public final class ConnectionFactory {
}
}
+ /**
+ * Updates the database schema by loading the upgrade script for the version specified. The intended use is that if the
+ * current schema version is 2.9 then we would call updateSchema(conn, "2.9"). This would load the upgrade_2.9.sql file and
+ * execute it against the database. The upgrade script must update the 'version' in the properties table.
+ *
+ * @param conn the database connection object
+ * @param schema the current schema version that is being upgraded
+ * @throws DatabaseException thrown if there is an exception upgrading the database schema
+ */
+ private static void updateSchema(Connection conn, String schema) throws DatabaseException {
+ LOGGER.debug("Updating database structure");
+ InputStream is;
+ InputStreamReader reader;
+ BufferedReader in = null;
+ String updateFile = null;
+ try {
+ updateFile = String.format(DB_STRUCTURE_UPDATE_RESOURCE, schema);
+ is = ConnectionFactory.class.getClassLoader().getResourceAsStream(updateFile);
+ reader = new InputStreamReader(is, "UTF-8");
+ in = new BufferedReader(reader);
+ final StringBuilder sb = new StringBuilder(2110);
+ String tmp;
+ while ((tmp = in.readLine()) != null) {
+ sb.append(tmp);
+ }
+ Statement statement = null;
+ try {
+ statement = conn.createStatement();
+ statement.execute(sb.toString());
+ } catch (SQLException ex) {
+ LOGGER.debug("", ex);
+ throw new DatabaseException("Unable to update database schema", ex);
+ } finally {
+ DBUtils.closeStatement(statement);
+ }
+ } catch (IOException ex) {
+ final String msg = String.format("Upgrade SQL file does not exist: %s", updateFile);
+ throw new DatabaseException(msg, ex);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ex) {
+ LOGGER.trace("", ex);
+ }
+ }
+ }
+ }
+
/**
* Uses the provided connection to check the specified schema version within the database.
*
@@ -288,12 +337,13 @@ public final class ConnectionFactory {
ResultSet rs = null;
CallableStatement cs = null;
try {
+ //TODO convert this to use DatabaseProperties
cs = conn.prepareCall("SELECT value FROM properties WHERE id = 'version'");
rs = cs.executeQuery();
if (rs.next()) {
- final boolean isWrongSchema = !DB_SCHEMA_VERSION.equals(rs.getString(1));
- if (isWrongSchema) {
- throw new DatabaseException("Incorrect database schema; unable to continue");
+ if (!DB_SCHEMA_VERSION.equals(rs.getString(1))) {
+ LOGGER.debug("Updating from version: " + rs.getString(1));
+ updateSchema(conn, rs.getString(1));
}
} else {
throw new DatabaseException("Database schema is missing");
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java
index 6d4a34f25..153c35cfd 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java
@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.data.nvdcve;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -766,8 +767,8 @@ public class CveDB {
DependencyVersion cpeVersion;
if (cpe.getVersion() != null && !cpe.getVersion().isEmpty()) {
String versionText;
- if (cpe.getRevision() != null && !cpe.getRevision().isEmpty()) {
- versionText = String.format("%s.%s", cpe.getVersion(), cpe.getRevision());
+ if (cpe.getUpdate() != null && !cpe.getUpdate().isEmpty()) {
+ versionText = String.format("%s.%s", cpe.getVersion(), cpe.getUpdate());
} else {
versionText = cpe.getVersion();
}
@@ -777,4 +778,41 @@ public class CveDB {
}
return cpeVersion;
}
+
+ /**
+ * Deletes unused dictionary entries from the database.
+ */
+ public void deleteUnusedCpe() {
+ CallableStatement cs = null;
+ try {
+ cs = getConnection().prepareCall(statementBundle.getString("DELETE_UNUSED_DICT_CPE"));
+ cs.executeUpdate();
+ } catch (SQLException ex) {
+ LOGGER.error("Unable to delete CPE dictionary entries", ex);
+ } finally {
+ DBUtils.closeStatement(cs);
+ }
+ }
+
+ /**
+ * Merges CPE entries into the database.
+ *
+ * @param cpe the CPE identifier
+ * @param vendor the CPE vendor
+ * @param product the CPE product
+ */
+ public void addCpe(String cpe, String vendor, String product) {
+ PreparedStatement ps = null;
+ try {
+ ps = getConnection().prepareCall(statementBundle.getString("ADD_DICT_CPE"));
+ ps.setString(1, cpe);
+ ps.setString(2, vendor);
+ ps.setString(3, product);
+ ps.executeUpdate();
+ } catch (SQLException ex) {
+ LOGGER.error("Unable to add CPE dictionary entry", ex);
+ } finally {
+ DBUtils.closeStatement(ps);
+ }
+ }
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java
index fc74931e3..f3ae9b50c 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java
@@ -24,7 +24,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.TreeMap;
-import org.owasp.dependencycheck.data.update.NvdCveInfo;
+import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,20 +41,28 @@ public class DatabaseProperties {
*/
private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseProperties.class);
/**
- * Modified key word, used as a key to store information about the modified file (i.e. the containing the last 8
- * days of updates)..
+ * Modified key word, used as a key to store information about the modified file (i.e. the containing the last 8 days of
+ * updates)..
*/
public static final String MODIFIED = "Modified";
/**
- * The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE
- * xml file.
+ * The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE xml file.
*/
public static final String LAST_UPDATED = "NVD CVE Modified";
/**
- * Stores the last updated time for each of the NVD CVE files. These timestamps should be updated if we process the
- * modified file within 7 days of the last update.
+ * Stores the last updated time for each of the NVD CVE files. These timestamps should be updated if we process the modified
+ * file within 7 days of the last update.
*/
public static final String LAST_UPDATED_BASE = "NVD CVE ";
+ /**
+ * The key for the last time the CPE data was updated.
+ */
+ public static final String LAST_CPE_UPDATE = "LAST_CPE_UPDATE";
+ /**
+ * The key for the database schema version.
+ */
+ public static final String VERSION = "version";
+
/**
* A collection of properties about the data.
*/
@@ -116,8 +124,7 @@ public class DatabaseProperties {
}
/**
- * Returns the property value for the given key. If the key is not contained in the underlying properties null is
- * returned.
+ * Returns the property value for the given key. If the key is not contained in the underlying properties null is returned.
*
* @param key the property key
* @return the value of the property
@@ -127,8 +134,8 @@ public class DatabaseProperties {
}
/**
- * Returns the property value for the given key. If the key is not contained in the underlying properties the
- * default value is returned.
+ * Returns the property value for the given key. If the key is not contained in the underlying properties the default value is
+ * returned.
*
* @param key the property key
* @param defaultValue the default value
@@ -148,8 +155,8 @@ public class DatabaseProperties {
}
/**
- * Returns a map of the meta data from the database properties. This primarily contains timestamps of when the NVD
- * CVE information was last updated.
+ * Returns a map of the meta data from the database properties. This primarily contains timestamps of when the NVD CVE
+ * information was last updated.
*
* @return a map of the database meta data
*/
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/BaseUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/BaseUpdater.java
new file mode 100644
index 000000000..e054e9303
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/BaseUpdater.java
@@ -0,0 +1,86 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2015 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.data.update;
+
+import org.owasp.dependencycheck.data.nvdcve.CveDB;
+import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
+import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author Jeremy Long
+ */
+public abstract class BaseUpdater {
+
+ /**
+ * Static logger.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(BaseUpdater.class);
+ /**
+ * Information about the timestamps and URLs for data that needs to be updated.
+ */
+ private DatabaseProperties properties;
+ /**
+ * Reference to the Cve Database.
+ */
+ private CveDB cveDB = null;
+
+ protected CveDB getCveDB() {
+ return cveDB;
+ }
+
+ protected DatabaseProperties getProperties() {
+ return properties;
+ }
+
+ /**
+ * Closes the CVE and CPE data stores.
+ */
+ protected void closeDataStores() {
+ if (cveDB != null) {
+ try {
+ cveDB.close();
+ } catch (Throwable ignore) {
+ LOGGER.trace("Error closing the database", ignore);
+ }
+ }
+ }
+
+ /**
+ * Opens the data store.
+ *
+ * @throws UpdateException thrown if a data store cannot be opened
+ */
+ protected final void openDataStores() throws UpdateException {
+ if (cveDB != null) {
+ return;
+ }
+ try {
+ cveDB = new CveDB();
+ cveDB.open();
+ } catch (DatabaseException ex) {
+ closeDataStores();
+ LOGGER.debug("Database Exception opening databases", ex);
+ throw new UpdateException("Error updating the database, please see the log file for more details.");
+ }
+ properties = cveDB.getDatabaseProperties();
+ }
+}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java
new file mode 100644
index 000000000..0f6707488
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/CpeUpdater.java
@@ -0,0 +1,198 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2015 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.data.update;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+import java.util.List;
+import java.util.zip.GZIPInputStream;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.apache.commons.io.FileUtils;
+import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.LAST_CPE_UPDATE;
+import org.owasp.dependencycheck.data.update.cpe.CPEHandler;
+import org.owasp.dependencycheck.data.update.cpe.Cpe;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
+import org.owasp.dependencycheck.utils.DateUtil;
+import org.owasp.dependencycheck.utils.DownloadFailedException;
+import org.owasp.dependencycheck.utils.Downloader;
+import org.owasp.dependencycheck.utils.Settings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * The CpeUpdater is designed to download the CPE data file from NIST and import the data into the database. However, as this
+ * currently adds no beneficial data, compared to what is in the CPE data contained in the CVE data files, this class is not
+ * currently used. The code is being kept as a future update may utilize more data from the CPE xml files.
+ *
+ * @author Jeremy Long
+ */
+public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
+
+ /**
+ * Static logger.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(CpeUpdater.class);
+
+ @Override
+ public void update() throws UpdateException {
+ try {
+ openDataStores();
+ if (updateNeeded()) {
+ LOGGER.info("Updating the Common Platform Enumeration (CPE)");
+ final File xml = downloadCpe();
+ final List cpes = processXML(xml);
+ getCveDB().deleteUnusedCpe();
+ for (Cpe cpe : cpes) {
+ getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
+ }
+ final Date now = new Date();
+ getProperties().save(LAST_CPE_UPDATE, Long.toString(now.getTime()));
+ LOGGER.info("CPE update complete");
+ }
+ } finally {
+ closeDataStores();
+ }
+ }
+
+ /**
+ * Downloads the CPE XML file.
+ *
+ * @return the file reference to the CPE.xml file
+ * @throws UpdateException thrown if there is an issue downloading the XML file
+ */
+ private File downloadCpe() throws UpdateException {
+ File xml;
+ final URL url;
+ try {
+ url = new URL(Settings.getString(Settings.KEYS.CPE_URL));
+ xml = File.createTempFile("cpe", ".xml", Settings.getTempDirectory());
+ Downloader.fetchFile(url, xml);
+ if (url.toExternalForm().endsWith(".xml.gz")) {
+ extractGzip(xml);
+ }
+
+ } catch (MalformedURLException ex) {
+ throw new UpdateException("Invalid CPE URL", ex);
+ } catch (DownloadFailedException ex) {
+ throw new UpdateException("Unable to download CPE XML file", ex);
+ } catch (IOException ex) {
+ throw new UpdateException("Unable to create temporary file to download CPE", ex);
+ }
+ return xml;
+ }
+
+ /**
+ * Parses the CPE XML file to return a list of CPE entries.
+ *
+ * @param xml the CPE data file
+ * @return the list of CPE entries
+ * @throws UpdateException thrown if there is an issue with parsing the XML file
+ */
+ private List processXML(final File xml) throws UpdateException {
+ try {
+ final SAXParserFactory factory = SAXParserFactory.newInstance();
+ final SAXParser saxParser = factory.newSAXParser();
+ final CPEHandler handler = new CPEHandler();
+ saxParser.parse(xml, handler);
+ return handler.getData();
+ } catch (ParserConfigurationException ex) {
+ throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Issue", ex);
+ } catch (SAXException ex) {
+ throw new UpdateException("Unable to parse CPE XML file due to SAX Parser Exception", ex);
+ } catch (IOException ex) {
+ throw new UpdateException("Unable to parse CPE XML file due to IO Failure", ex);
+ }
+ }
+
+ /**
+ * Checks to find the last time the CPE data was refreshed and if it needs to be updated.
+ *
+ * @return true if the CPE data should be refreshed
+ */
+ private boolean updateNeeded() {
+ final Date now = new Date();
+ final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 30);
+ long timestamp = 0;
+ final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
+ if (ts != null && ts.matches("^[0-9]+$")) {
+ timestamp = Long.parseLong(ts);
+ }
+ return !DateUtil.withinDateRange(timestamp, now.getTime(), days);
+ }
+
+ /**
+ * Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file specified.
+ *
+ * @param file the archive file
+ * @throws FileNotFoundException thrown if the file does not exist
+ * @throws IOException thrown if there is an error extracting the file.
+ */
+ private void extractGzip(File file) throws FileNotFoundException, IOException {
+ //TODO - move this to a util class as it is duplicative of (copy of) code in the DownloadTask
+ final String originalPath = file.getPath();
+ final File gzip = new File(originalPath + ".gz");
+ if (gzip.isFile() && !gzip.delete()) {
+ gzip.deleteOnExit();
+ }
+ if (!file.renameTo(gzip)) {
+ throw new IOException("Unable to rename '" + file.getPath() + "'");
+ }
+ final File newfile = new File(originalPath);
+
+ final byte[] buffer = new byte[4096];
+
+ GZIPInputStream cin = null;
+ FileOutputStream out = null;
+ try {
+ cin = new GZIPInputStream(new FileInputStream(gzip));
+ out = new FileOutputStream(newfile);
+
+ int len;
+ while ((len = cin.read(buffer)) > 0) {
+ out.write(buffer, 0, len);
+ }
+ } finally {
+ if (cin != null) {
+ try {
+ cin.close();
+ } catch (IOException ex) {
+ LOGGER.trace("ignore", ex);
+ }
+ }
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException ex) {
+ LOGGER.trace("ignore", ex);
+ }
+ }
+ if (gzip.isFile()) {
+ FileUtils.deleteQuietly(gzip);
+ }
+ }
+ }
+}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java
index a6b602fd8..ef9aa2846 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java
@@ -18,23 +18,44 @@
package org.owasp.dependencycheck.data.update;
import java.net.MalformedURLException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
+import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED;
+import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
+import org.owasp.dependencycheck.data.update.nvd.DownloadTask;
+import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
+import org.owasp.dependencycheck.data.update.nvd.ProcessTask;
+import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve;
+import org.owasp.dependencycheck.utils.DateUtil;
import org.owasp.dependencycheck.utils.DownloadFailedException;
+import org.owasp.dependencycheck.utils.InvalidSettingException;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Class responsible for updating the NVD CVE and CPE data stores.
+ * Class responsible for updating the NVD CVE data.
*
* @author Jeremy Long
*/
-public class NvdCveUpdater implements CachedWebDataSource {
+public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
/**
* The logger
*/
private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveUpdater.class);
+ /**
+ * The max thread pool size to use when downloading files.
+ */
+ public static final int MAX_THREAD_POOL_SIZE = Settings.getInt(Settings.KEYS.MAX_DOWNLOAD_THREAD_POOL_SIZE, 3);
/**
*
@@ -45,9 +66,10 @@ public class NvdCveUpdater implements CachedWebDataSource {
@Override
public void update() throws UpdateException {
try {
- final StandardUpdate task = new StandardUpdate();
- if (task.isUpdateNeeded()) {
- task.update();
+ openDataStores();
+ final UpdateableNvdCve updateable = getUpdatesNeeded();
+ if (updateable.isUpdateNeeded()) {
+ performUpdate(updateable);
}
} catch (MalformedURLException ex) {
LOGGER.warn(
@@ -61,6 +83,203 @@ public class NvdCveUpdater implements CachedWebDataSource {
"If you are behind a proxy you may need to configure dependency-check to use the proxy.");
}
LOGGER.debug("", ex);
+ } finally {
+ closeDataStores();
}
}
+
+ /**
+ * Downloads the latest NVD CVE XML file from the web and imports it into the current CVE Database.
+ *
+ * @param updateable a collection of NVD CVE data file references that need to be downloaded and processed to update the
+ * database
+ * @throws UpdateException is thrown if there is an error updating the database
+ */
+ public void performUpdate(UpdateableNvdCve updateable) throws UpdateException {
+ int maxUpdates = 0;
+ try {
+ for (NvdCveInfo cve : updateable) {
+ if (cve.getNeedsUpdate()) {
+ maxUpdates += 1;
+ }
+ }
+ if (maxUpdates <= 0) {
+ return;
+ }
+ if (maxUpdates > 3) {
+ LOGGER.info(
+ "NVD CVE requires several updates; this could take a couple of minutes.");
+ }
+ if (maxUpdates > 0) {
+ openDataStores();
+ }
+
+ final int poolSize = (MAX_THREAD_POOL_SIZE < maxUpdates) ? MAX_THREAD_POOL_SIZE : maxUpdates;
+
+ final ExecutorService downloadExecutors = Executors.newFixedThreadPool(poolSize);
+ final ExecutorService processExecutor = Executors.newSingleThreadExecutor();
+ final Set>> downloadFutures = new HashSet>>(maxUpdates);
+ for (NvdCveInfo cve : updateable) {
+ if (cve.getNeedsUpdate()) {
+ final DownloadTask call = new DownloadTask(cve, processExecutor, getCveDB(), Settings.getInstance());
+ downloadFutures.add(downloadExecutors.submit(call));
+ }
+ }
+ downloadExecutors.shutdown();
+
+ //next, move the future future processTasks to just future processTasks
+ final Set> processFutures = new HashSet>(maxUpdates);
+ for (Future> future : downloadFutures) {
+ Future task = null;
+ try {
+ task = future.get();
+ } catch (InterruptedException ex) {
+ downloadExecutors.shutdownNow();
+ processExecutor.shutdownNow();
+
+ LOGGER.debug("Thread was interrupted during download", ex);
+ throw new UpdateException("The download was interrupted", ex);
+ } catch (ExecutionException ex) {
+ downloadExecutors.shutdownNow();
+ processExecutor.shutdownNow();
+
+ LOGGER.debug("Thread was interrupted during download execution", ex);
+ throw new UpdateException("The execution of the download was interrupted", ex);
+ }
+ if (task == null) {
+ downloadExecutors.shutdownNow();
+ processExecutor.shutdownNow();
+ LOGGER.debug("Thread was interrupted during download");
+ throw new UpdateException("The download was interrupted; unable to complete the update");
+ } else {
+ processFutures.add(task);
+ }
+ }
+
+ for (Future future : processFutures) {
+ try {
+ final ProcessTask task = future.get();
+ if (task.getException() != null) {
+ throw task.getException();
+ }
+ } catch (InterruptedException ex) {
+ processExecutor.shutdownNow();
+ LOGGER.debug("Thread was interrupted during processing", ex);
+ throw new UpdateException(ex);
+ } catch (ExecutionException ex) {
+ processExecutor.shutdownNow();
+ LOGGER.debug("Execution Exception during process", ex);
+ throw new UpdateException(ex);
+ } finally {
+ processExecutor.shutdown();
+ }
+ }
+
+ if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
+ getProperties().save(updateable.get(MODIFIED));
+ LOGGER.info("Begin database maintenance.");
+ getCveDB().cleanupDatabase();
+ LOGGER.info("End database maintenance.");
+ }
+ } finally {
+ closeDataStores();
+ }
+ }
+
+ /**
+ * Determines if the index needs to be updated. This is done by fetching the NVD CVE meta data and checking the last update
+ * date. If the data needs to be refreshed this method will return the NvdCveUrl for the files that need to be updated.
+ *
+ * @return the collection of files that need to be updated
+ * @throws MalformedURLException is thrown if the URL for the NVD CVE Meta data is incorrect
+ * @throws DownloadFailedException is thrown if there is an error. downloading the NVD CVE download data file
+ * @throws UpdateException Is thrown if there is an issue with the last updated properties file
+ */
+ protected final UpdateableNvdCve getUpdatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
+ UpdateableNvdCve updates = null;
+ try {
+ updates = retrieveCurrentTimestampsFromWeb();
+ } catch (InvalidDataException ex) {
+ final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
+ LOGGER.debug(msg, ex);
+ throw new DownloadFailedException(msg, ex);
+ } catch (InvalidSettingException ex) {
+ LOGGER.debug("Invalid setting found when retrieving timestamps", ex);
+ throw new DownloadFailedException("Invalid settings", ex);
+ }
+
+ if (updates == null) {
+ throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
+ }
+ if (!getProperties().isEmpty()) {
+ try {
+ final long lastUpdated = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED, "0"));
+ final Date now = new Date();
+ final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
+ if (lastUpdated == updates.getTimeStamp(MODIFIED)) {
+ updates.clear(); //we don't need to update anything.
+ } else if (DateUtil.withinDateRange(lastUpdated, now.getTime(), days)) {
+ for (NvdCveInfo entry : updates) {
+ if (MODIFIED.equals(entry.getId())) {
+ entry.setNeedsUpdate(true);
+ } else {
+ entry.setNeedsUpdate(false);
+ }
+ }
+ } else { //we figure out which of the several XML files need to be downloaded.
+ for (NvdCveInfo entry : updates) {
+ if (MODIFIED.equals(entry.getId())) {
+ entry.setNeedsUpdate(true);
+ } else {
+ long currentTimestamp = 0;
+ try {
+ currentTimestamp = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED_BASE
+ + entry.getId(), "0"));
+ } catch (NumberFormatException ex) {
+ LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated",
+ DatabaseProperties.LAST_UPDATED_BASE, entry.getId(), ex);
+ }
+ if (currentTimestamp == entry.getTimestamp()) {
+ entry.setNeedsUpdate(false);
+ }
+ }
+ }
+ }
+ } catch (NumberFormatException ex) {
+ LOGGER.warn("An invalid schema version or timestamp exists in the data.properties file.");
+ LOGGER.debug("", ex);
+ }
+ }
+ return updates;
+ }
+
+ /**
+ * Retrieves the timestamps from the NVD CVE meta data file.
+ *
+ * @return the timestamp from the currently published nvdcve downloads page
+ * @throws MalformedURLException thrown if the URL for the NVD CCE Meta data is incorrect.
+ * @throws DownloadFailedException thrown if there is an error downloading the nvd cve meta data file
+ * @throws InvalidDataException thrown if there is an exception parsing the timestamps
+ * @throws InvalidSettingException thrown if the settings are invalid
+ */
+ private UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
+ throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
+
+ final UpdateableNvdCve updates = new UpdateableNvdCve();
+ updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL),
+ Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
+ false);
+
+ final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
+ final int end = Calendar.getInstance().get(Calendar.YEAR);
+ final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
+ final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
+ for (int i = start; i <= end; i++) {
+ updates.add(Integer.toString(i), String.format(baseUrl20, i),
+ String.format(baseUrl12, i),
+ true);
+ }
+ return updates;
+ }
+
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/StandardUpdate.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/StandardUpdate.java
deleted file mode 100644
index d5f1c2c22..000000000
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/StandardUpdate.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * This file is part of dependency-check-core.
- *
- * 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.
- *
- * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
- */
-package org.owasp.dependencycheck.data.update;
-
-import java.net.MalformedURLException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import org.owasp.dependencycheck.data.nvdcve.CveDB;
-import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
-import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
-import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED;
-import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
-import org.owasp.dependencycheck.data.update.exception.UpdateException;
-import org.owasp.dependencycheck.data.update.task.DownloadTask;
-import org.owasp.dependencycheck.data.update.task.ProcessTask;
-import org.owasp.dependencycheck.utils.DateUtil;
-import org.owasp.dependencycheck.utils.DownloadFailedException;
-import org.owasp.dependencycheck.utils.InvalidSettingException;
-import org.owasp.dependencycheck.utils.Settings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Class responsible for updating the NVDCVE data store.
- *
- * @author Jeremy Long
- */
-public class StandardUpdate {
-
- /**
- * Static logger.
- */
- private static final Logger LOGGER = LoggerFactory.getLogger(StandardUpdate.class);
- /**
- * The max thread pool size to use when downloading files.
- */
- public static final int MAX_THREAD_POOL_SIZE = Settings.getInt(Settings.KEYS.MAX_DOWNLOAD_THREAD_POOL_SIZE, 3);
- /**
- * Information about the timestamps and URLs for data that needs to be updated.
- */
- private DatabaseProperties properties;
- /**
- * A collection of updateable NVD CVE items.
- */
- private UpdateableNvdCve updateable;
- /**
- * Reference to the Cve Database.
- */
- private CveDB cveDB = null;
-
- /**
- * Gets whether or not an update is needed.
- *
- * @return true or false depending on whether an update is needed
- */
- public boolean isUpdateNeeded() {
- return updateable.isUpdateNeeded();
- }
-
- /**
- * Constructs a new Standard Update Task.
- *
- * @throws MalformedURLException thrown if a configured URL is malformed
- * @throws DownloadFailedException thrown if a timestamp cannot be checked on a configured URL
- * @throws UpdateException thrown if there is an exception generating the update task
- */
- public StandardUpdate() throws MalformedURLException, DownloadFailedException, UpdateException {
- openDataStores();
- properties = cveDB.getDatabaseProperties();
- updateable = updatesNeeded();
- }
-
- /**
- *
- * Downloads the latest NVD CVE XML file from the web and imports it into the current CVE Database.
- *
- * @throws UpdateException is thrown if there is an error updating the database
- */
- public void update() throws UpdateException {
- int maxUpdates = 0;
- try {
- for (NvdCveInfo cve : updateable) {
- if (cve.getNeedsUpdate()) {
- maxUpdates += 1;
- }
- }
- if (maxUpdates <= 0) {
- return;
- }
- if (maxUpdates > 3) {
- LOGGER.info(
- "NVD CVE requires several updates; this could take a couple of minutes.");
- }
- if (maxUpdates > 0) {
- openDataStores();
- }
-
- final int poolSize = (MAX_THREAD_POOL_SIZE < maxUpdates) ? MAX_THREAD_POOL_SIZE : maxUpdates;
-
- final ExecutorService downloadExecutors = Executors.newFixedThreadPool(poolSize);
- final ExecutorService processExecutor = Executors.newSingleThreadExecutor();
- final Set>> downloadFutures = new HashSet>>(maxUpdates);
- for (NvdCveInfo cve : updateable) {
- if (cve.getNeedsUpdate()) {
- final DownloadTask call = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance());
- downloadFutures.add(downloadExecutors.submit(call));
- }
- }
- downloadExecutors.shutdown();
-
- //next, move the future future processTasks to just future processTasks
- final Set> processFutures = new HashSet>(maxUpdates);
- for (Future> future : downloadFutures) {
- Future task = null;
- try {
- task = future.get();
- } catch (InterruptedException ex) {
- downloadExecutors.shutdownNow();
- processExecutor.shutdownNow();
-
- LOGGER.debug("Thread was interrupted during download", ex);
- throw new UpdateException("The download was interrupted", ex);
- } catch (ExecutionException ex) {
- downloadExecutors.shutdownNow();
- processExecutor.shutdownNow();
-
- LOGGER.debug("Thread was interrupted during download execution", ex);
- throw new UpdateException("The execution of the download was interrupted", ex);
- }
- if (task == null) {
- downloadExecutors.shutdownNow();
- processExecutor.shutdownNow();
- LOGGER.debug("Thread was interrupted during download");
- throw new UpdateException("The download was interrupted; unable to complete the update");
- } else {
- processFutures.add(task);
- }
- }
-
- for (Future future : processFutures) {
- try {
- final ProcessTask task = future.get();
- if (task.getException() != null) {
- throw task.getException();
- }
- } catch (InterruptedException ex) {
- processExecutor.shutdownNow();
- LOGGER.debug("Thread was interrupted during processing", ex);
- throw new UpdateException(ex);
- } catch (ExecutionException ex) {
- processExecutor.shutdownNow();
- LOGGER.debug("Execution Exception during process", ex);
- throw new UpdateException(ex);
- } finally {
- processExecutor.shutdown();
- }
- }
-
- if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
- properties.save(updateable.get(MODIFIED));
- LOGGER.info("Begin database maintenance.");
- cveDB.cleanupDatabase();
- LOGGER.info("End database maintenance.");
- }
- } finally {
- closeDataStores();
- }
- }
-
- /**
- * Determines if the index needs to be updated. This is done by fetching the NVD CVE meta data and checking the last update
- * date. If the data needs to be refreshed this method will return the NvdCveUrl for the files that need to be updated.
- *
- * @return the collection of files that need to be updated
- * @throws MalformedURLException is thrown if the URL for the NVD CVE Meta data is incorrect
- * @throws DownloadFailedException is thrown if there is an error. downloading the NVD CVE download data file
- * @throws UpdateException Is thrown if there is an issue with the last updated properties file
- */
- protected final UpdateableNvdCve updatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
- UpdateableNvdCve updates = null;
- try {
- updates = retrieveCurrentTimestampsFromWeb();
- } catch (InvalidDataException ex) {
- final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
- LOGGER.debug(msg, ex);
- throw new DownloadFailedException(msg, ex);
- } catch (InvalidSettingException ex) {
- LOGGER.debug("Invalid setting found when retrieving timestamps", ex);
- throw new DownloadFailedException("Invalid settings", ex);
- }
-
- if (updates == null) {
- throw new DownloadFailedException("Unable to retrieve the timestamps of the currently published NVD CVE data");
- }
- if (!properties.isEmpty()) {
- try {
- final long lastUpdated = Long.parseLong(properties.getProperty(DatabaseProperties.LAST_UPDATED, "0"));
- final Date now = new Date();
- final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
- if (lastUpdated == updates.getTimeStamp(MODIFIED)) {
- updates.clear(); //we don't need to update anything.
- } else if (DateUtil.withinDateRange(lastUpdated, now.getTime(), days)) {
- for (NvdCveInfo entry : updates) {
- if (MODIFIED.equals(entry.getId())) {
- entry.setNeedsUpdate(true);
- } else {
- entry.setNeedsUpdate(false);
- }
- }
- } else { //we figure out which of the several XML files need to be downloaded.
- for (NvdCveInfo entry : updates) {
- if (MODIFIED.equals(entry.getId())) {
- entry.setNeedsUpdate(true);
- } else {
- long currentTimestamp = 0;
- try {
- currentTimestamp = Long.parseLong(properties.getProperty(DatabaseProperties.LAST_UPDATED_BASE + entry.getId(), "0"));
- } catch (NumberFormatException ex) {
- LOGGER.debug("Error parsing '{}' '{}' from nvdcve.lastupdated",
- DatabaseProperties.LAST_UPDATED_BASE, entry.getId(), ex);
- }
- if (currentTimestamp == entry.getTimestamp()) {
- entry.setNeedsUpdate(false);
- }
- }
- }
- }
- } catch (NumberFormatException ex) {
- LOGGER.warn("An invalid schema version or timestamp exists in the data.properties file.");
- LOGGER.debug("", ex);
- }
- }
- return updates;
- }
-
- /**
- * Retrieves the timestamps from the NVD CVE meta data file.
- *
- * @return the timestamp from the currently published nvdcve downloads page
- * @throws MalformedURLException thrown if the URL for the NVD CCE Meta data is incorrect.
- * @throws DownloadFailedException thrown if there is an error downloading the nvd cve meta data file
- * @throws InvalidDataException thrown if there is an exception parsing the timestamps
- * @throws InvalidSettingException thrown if the settings are invalid
- */
- private UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
- throws MalformedURLException, DownloadFailedException, InvalidDataException, InvalidSettingException {
-
- final UpdateableNvdCve updates = new UpdateableNvdCve();
- updates.add(MODIFIED, Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL),
- Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL),
- false);
-
- final int start = Settings.getInt(Settings.KEYS.CVE_START_YEAR);
- final int end = Calendar.getInstance().get(Calendar.YEAR);
- final String baseUrl20 = Settings.getString(Settings.KEYS.CVE_SCHEMA_2_0);
- final String baseUrl12 = Settings.getString(Settings.KEYS.CVE_SCHEMA_1_2);
- for (int i = start; i <= end; i++) {
- updates.add(Integer.toString(i), String.format(baseUrl20, i),
- String.format(baseUrl12, i),
- true);
- }
-
- return updates;
- }
-
- /**
- * Closes the CVE and CPE data stores.
- */
- protected void closeDataStores() {
- if (cveDB != null) {
- try {
- cveDB.close();
- } catch (Throwable ignore) {
- LOGGER.trace("Error closing the cveDB", ignore);
- }
- }
- }
-
- /**
- * Opens the CVE and CPE data stores.
- *
- * @throws UpdateException thrown if a data store cannot be opened
- */
- protected final void openDataStores() throws UpdateException {
- if (cveDB != null) {
- return;
- }
- try {
- cveDB = new CveDB();
- cveDB.open();
- } catch (DatabaseException ex) {
- closeDataStores();
- LOGGER.debug("Database Exception opening databases", ex);
- throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
- }
- }
-}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java
new file mode 100644
index 000000000..6a155c6ca
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CPEHandler.java
@@ -0,0 +1,364 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2015 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.data.update.cpe;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import org.owasp.dependencycheck.data.update.NvdCveUpdater;
+import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A SAX Handler that will parse the CPE XML and load it into the databse.
+ *
+ * @author Jeremy Long
+ */
+public class CPEHandler extends DefaultHandler {
+
+ /**
+ * The current CPE schema.
+ */
+ private static final String CURRENT_SCHEMA_VERSION = "2.3";
+ /**
+ * The text content of the node being processed. This can be used during the end element event.
+ */
+ private StringBuilder nodeText = null;
+ /**
+ * A reference to the current element.
+ */
+ private Element current = new Element();
+ /**
+ * The logger.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveUpdater.class);
+ /**
+ * The list of CPE values.
+ */
+ private List data = new ArrayList();
+
+ /**
+ * Returns the list of CPE values.
+ *
+ * @return the list of CPE values
+ */
+ public List getData() {
+ return data;
+ }
+
+ /**
+ * Handles the start element event.
+ *
+ * @param uri the elements uri
+ * @param localName the local name
+ * @param qName the qualified name
+ * @param attributes the attributes
+ * @throws SAXException thrown if there is an exception processing the element
+ */
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ nodeText = null;
+ current.setNode(qName);
+ if (current.isCpeItemNode()) {
+ final String temp = attributes.getValue("deprecated");
+ final String value = attributes.getValue("name");
+ final boolean delete = "true".equalsIgnoreCase(temp);
+ if (!delete && value.startsWith("cpe:/a:") && value.length() > 7) {
+ try {
+ final Cpe cpe = new Cpe(value);
+ data.add(cpe);
+ } catch (UnsupportedEncodingException ex) {
+ LOGGER.debug("Unable to parse the CPE", ex);
+ } catch (InvalidDataException ex) {
+ LOGGER.debug("CPE is not the correct format", ex);
+ }
+ }
+ } else if (current.isSchemaVersionNode()) {
+ nodeText = new StringBuilder(3);
+ }
+// } else if (current.isTitleNode()) {
+// //do nothing
+// } else if (current.isMetaNode()) {
+// //do nothing
+// } else if (current.isTimestampNode()) {
+// //do nothing
+// } else if (current.isCpeListNode()) {
+// //do nothing
+// } else if (current.isNotesNode()) {
+// //do nothing
+// } else if (current.isNoteNode()) {
+// //do nothing
+// } else if (current.isCheckNode()) {
+// //do nothing
+// } else if (current.isGeneratorNode()) {
+// //do nothing
+// } else if (current.isProductNameNode()) {
+// //do nothing
+// } else if (current.isProductVersionNode()) {
+// //do nothing
+ }
+
+ /**
+ * Reads the characters in the current node.
+ *
+ * @param ch the char array
+ * @param start the start position of the data read
+ * @param length the length of the data read
+ * @throws SAXException thrown if there is an exception processing the characters
+ */
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ if (nodeText != null) {
+ nodeText.append(ch, start, length);
+ }
+ }
+
+ /**
+ * Handles the end element event. Stores the CPE data in the Cve Database if the cpe item node is ending.
+ *
+ * @param uri the element's uri
+ * @param localName the local name
+ * @param qName the qualified name
+ * @throws SAXException thrown if there is an exception processing the element
+ */
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ current.setNode(qName);
+ if (current.isSchemaVersionNode() && !CURRENT_SCHEMA_VERSION.equals(nodeText.toString())) {
+ throw new SAXException("ERROR: Unexpecgted CPE Schema Version, expected: "
+ + CURRENT_SCHEMA_VERSION + ", file is: " + nodeText);
+
+ }
+// } else if (current.isCpeItemNode()) {
+// //do nothing
+// } else if (current.isTitleNode()) {
+// //do nothing
+// } else if (current.isCpeListNode()) {
+// //do nothing
+// } else if (current.isMetaNode()) {
+// //do nothing
+// } else if (current.isNotesNode()) {
+// //do nothing
+// } else if (current.isNoteNode()) {
+// //do nothing
+// } else if (current.isCheckNode()) {
+// //do nothing
+// } else if (current.isGeneratorNode()) {
+// //do nothing
+// } else if (current.isProductNameNode()) {
+// //do nothing
+// } else if (current.isProductVersionNode()) {
+// //do nothing
+// else if (current.isTimestampNode()) {
+// //do nothing
+// } else {
+// throw new SAXException("ERROR STATE: Unexpected qName '" + qName + "'");
+// }
+ }
+
+ //
+ /**
+ * A simple class to maintain information about the current element while parsing the CPE XML.
+ */
+ protected class Element {
+
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String CPE_LIST = "cpe-list";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String CPE_ITEM = "cpe-item";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String TITLE = "title";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String NOTES = "notes";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String NOTE = "note";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String CHECK = "check";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String META = "meta:item-metadata";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String GENERATOR = "generator";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String PRODUCT_NAME = "product_name";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String PRODUCT_VERSION = "product_version";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String SCHEMA_VERSION = "schema_version";
+ /**
+ * A node type in the CPE Schema 2.2
+ */
+ public static final String TIMESTAMP = "timestamp";
+ /**
+ * A reference to the current node.
+ */
+ private String node = null;
+
+ /**
+ * Gets the value of node
+ *
+ * @return the value of node
+ */
+ public String getNode() {
+ return this.node;
+ }
+
+ /**
+ * Sets the value of node
+ *
+ * @param node new value of node
+ */
+ public void setNode(String node) {
+ this.node = node;
+ }
+
+ /**
+ * Checks if the handler is at the CPE_LIST node
+ *
+ * @return true or false
+ */
+ public boolean isCpeListNode() {
+ return CPE_LIST.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the CPE_ITEM node
+ *
+ * @return true or false
+ */
+ public boolean isCpeItemNode() {
+ return CPE_ITEM.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the TITLE node
+ *
+ * @return true or false
+ */
+ public boolean isTitleNode() {
+ return TITLE.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the NOTES node
+ *
+ * @return true or false
+ */
+ public boolean isNotesNode() {
+ return NOTES.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the NOTE node
+ *
+ * @return true or false
+ */
+ public boolean isNoteNode() {
+ return NOTE.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the CHECK node
+ *
+ * @return true or false
+ */
+ public boolean isCheckNode() {
+ return CHECK.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the META node
+ *
+ * @return true or false
+ */
+ public boolean isMetaNode() {
+ return META.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the GENERATOR node
+ *
+ * @return true or false
+ */
+ public boolean isGeneratorNode() {
+ return GENERATOR.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the PRODUCT_NAME node
+ *
+ * @return true or false
+ */
+ public boolean isProductNameNode() {
+ return PRODUCT_NAME.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the PRODUCT_VERSION node
+ *
+ * @return true or false
+ */
+ public boolean isProductVersionNode() {
+ return PRODUCT_VERSION.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the SCHEMA_VERSION node
+ *
+ * @return true or false
+ */
+ public boolean isSchemaVersionNode() {
+ return SCHEMA_VERSION.equals(node);
+ }
+
+ /**
+ * Checks if the handler is at the TIMESTAMP node
+ *
+ * @return true or false
+ */
+ public boolean isTimestampNode() {
+ return TIMESTAMP.equals(node);
+ }
+ }
+ //
+}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java
new file mode 100644
index 000000000..1d4c3cb33
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/Cpe.java
@@ -0,0 +1,125 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2015 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.data.update.cpe;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
+
+/**
+ *
+ * @author Jeremy Long
+ */
+public class Cpe {
+
+ /**
+ * Constructs a new Cpe Object by parsing the vendor and product from the CPE identifier value.
+ *
+ * @param value the cpe identifier (cpe:/a:vendor:product:version:....)
+ * @throws UnsupportedEncodingException thrown if UTF-8 is not supported
+ * @throws InvalidDataException thrown if the CPE provided is not the correct format
+ */
+ public Cpe(String value) throws UnsupportedEncodingException, InvalidDataException {
+ this.value = value;
+ final String[] data = value.substring(7).split(":");
+ if (data.length >= 2) {
+ vendor = URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8");
+ product = URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8");
+ } else {
+ throw new InvalidDataException(String.format("CPE has an invalid format: %s", value));
+ }
+ }
+
+ /**
+ * The CPE identifier string (cpe:/a:vendor:product:version).
+ */
+ private String value;
+
+ /**
+ * Get the value of value.
+ *
+ * @return the value of value
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Set the value of value.
+ *
+ * @param value new value of value
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+ /**
+ * The vendor portion of the identifier.
+ */
+ private String vendor;
+
+ /**
+ * Get the value of vendor.
+ *
+ * @return the value of vendor
+ */
+ public String getVendor() {
+ return vendor;
+ }
+
+ /**
+ * Set the value of vendor.
+ *
+ * @param vendor new value of vendor
+ */
+ public void setVendor(String vendor) {
+ this.vendor = vendor;
+ }
+
+ /**
+ * The product portion of the identifier.
+ */
+ private String product;
+
+ /**
+ * Get the value of product.
+ *
+ * @return the value of product
+ */
+ public String getProduct() {
+ return product;
+ }
+
+ /**
+ * Set the value of product.
+ *
+ * @param product new value of product
+ */
+ public void setProduct(String product) {
+ this.product = product;
+ }
+
+ /**
+ * Returns the full CPE identifier.
+ *
+ * @return the full CPE identifier
+ */
+ @Override
+ public String toString() {
+ return value;
+ }
+}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/package-info.java
new file mode 100644
index 000000000..3176a4ea5
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/cpe/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Contains classes used to parse the CPE XML file from NIST.
+ *
+ * These classes are not used as they add no value over the existing CPE data contained within the CVE data from the NVD. However,
+ * we may consider pulling the more descriptive data from the CPE data in the future.
+ */
+package org.owasp.dependencycheck.data.update.cpe;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/DownloadTask.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java
similarity index 96%
rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/DownloadTask.java
rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java
index 3365c179b..ed1ab22bc 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/DownloadTask.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java
@@ -15,7 +15,7 @@
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update.task;
+package org.owasp.dependencycheck.data.update.nvd;
import java.io.File;
import java.io.FileInputStream;
@@ -29,7 +29,6 @@ import java.util.concurrent.Future;
import java.util.zip.GZIPInputStream;
import org.apache.commons.io.FileUtils;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
-import org.owasp.dependencycheck.data.update.NvdCveInfo;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
@@ -55,8 +54,8 @@ public class DownloadTask implements Callable> {
* @param nvdCveInfo the NVD CVE info
* @param processor the processor service to submit the downloaded files to
* @param cveDB the CVE DB to use to store the vulnerability data
- * @param settings a reference to the global settings object; this is necessary so that when the thread is started
- * the dependencies have a correct reference to the global settings.
+ * @param settings a reference to the global settings object; this is necessary so that when the thread is started the
+ * dependencies have a correct reference to the global settings.
* @throws UpdateException thrown if temporary files could not be created
*/
public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
@@ -248,8 +247,7 @@ public class DownloadTask implements Callable> {
}
/**
- * Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file
- * specified.
+ * Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file specified.
*
* @param file the archive file
* @throws FileNotFoundException thrown if the file does not exist
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve12Handler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve12Handler.java
similarity index 99%
rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve12Handler.java
rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve12Handler.java
index 453f35b6b..26811ae7b 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve12Handler.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve12Handler.java
@@ -15,7 +15,7 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update.xml;
+package org.owasp.dependencycheck.data.update.nvd;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve20Handler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve20Handler.java
similarity index 99%
rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve20Handler.java
rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve20Handler.java
index 1ecabd763..e2b60db7a 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/NvdCve20Handler.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCve20Handler.java
@@ -15,7 +15,7 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update.xml;
+package org.owasp.dependencycheck.data.update.nvd;
import java.io.IOException;
import java.util.List;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveInfo.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java
similarity index 98%
rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveInfo.java
rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java
index 45d366eb6..a143000a8 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveInfo.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java
@@ -15,7 +15,7 @@
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update;
+package org.owasp.dependencycheck.data.update.nvd;
/**
* A pojo that contains the Url and timestamp of the current NvdCve XML files.
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/ProcessTask.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java
similarity index 94%
rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/ProcessTask.java
rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java
index bb0583ad7..8934337c9 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/ProcessTask.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java
@@ -15,7 +15,7 @@
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update.task;
+package org.owasp.dependencycheck.data.update.nvd;
import java.io.File;
import java.io.FileNotFoundException;
@@ -31,8 +31,6 @@ import org.owasp.dependencycheck.data.nvdcve.CveDB;
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
import org.owasp.dependencycheck.data.update.exception.UpdateException;
-import org.owasp.dependencycheck.data.update.xml.NvdCve12Handler;
-import org.owasp.dependencycheck.data.update.xml.NvdCve20Handler;
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
import org.owasp.dependencycheck.utils.Settings;
import org.slf4j.Logger;
@@ -94,8 +92,8 @@ public class ProcessTask implements Callable {
*
* @param cveDB the data store object
* @param filePair the download task that contains the URL references to download
- * @param settings a reference to the global settings object; this is necessary so that when the thread is started
- * the dependencies have a correct reference to the global settings.
+ * @param settings a reference to the global settings object; this is necessary so that when the thread is started the
+ * dependencies have a correct reference to the global settings.
*/
public ProcessTask(final CveDB cveDB, final DownloadTask filePair, Settings settings) {
this.cveDB = cveDB;
@@ -108,8 +106,8 @@ public class ProcessTask implements Callable {
* Implements the callable interface.
*
* @return this object
- * @throws Exception thrown if there is an exception; note that any UpdateExceptions are simply added to the tasks
- * exception collection
+ * @throws Exception thrown if there is an exception; note that any UpdateExceptions are simply added to the tasks exception
+ * collection
*/
@Override
public ProcessTask call() throws Exception {
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateableNvdCve.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java
similarity index 95%
rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateableNvdCve.java
rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java
index 6fc48d0be..2b2cf22b3 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/UpdateableNvdCve.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCve.java
@@ -15,7 +15,7 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update;
+package org.owasp.dependencycheck.data.update.nvd;
import java.net.MalformedURLException;
import java.net.URL;
@@ -27,8 +27,8 @@ import org.owasp.dependencycheck.utils.DownloadFailedException;
import org.owasp.dependencycheck.utils.Downloader;
/**
- * Contains a collection of updateable NvdCveInfo objects. This is used to determine which files need to be downloaded
- * and processed.
+ * Contains a collection of updateable NvdCveInfo objects. This is used to determine which files need to be downloaded and
+ * processed.
*
* @author Jeremy Long
*/
@@ -67,8 +67,7 @@ public class UpdateableNvdCve implements java.lang.Iterable, Iterato
*
* @param id the key for the item to be added
* @param url the URL to download the item
- * @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we
- * need).
+ * @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we need).
* @throws MalformedURLException thrown if the URL provided is invalid
* @throws DownloadFailedException thrown if the download fails.
*/
@@ -81,8 +80,7 @@ public class UpdateableNvdCve implements java.lang.Iterable, Iterato
*
* @param id the key for the item to be added
* @param url the URL to download the item
- * @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we
- * need).
+ * @param oldUrl the URL for the old version of the item (the NVD CVE old schema still contains useful data we need).
* @param needsUpdate whether or not the data needs to be updated
* @throws MalformedURLException thrown if the URL provided is invalid
* @throws DownloadFailedException thrown if the download fails.
@@ -175,7 +173,7 @@ public class UpdateableNvdCve implements java.lang.Iterable, Iterato
* @param key the key to lookup the return value
* @return the NvdCveInfo object stored using the specified key
*/
- NvdCveInfo get(String key) {
+ public NvdCveInfo get(String key) {
return collection.get(key);
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java
new file mode 100644
index 000000000..7e061da07
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains classes used to download, parse, and load the NVD CVE data from NIST into the local database.
+ */
+package org.owasp.dependencycheck.data.update.nvd;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/package-info.java
deleted file mode 100644
index 0d9385edd..000000000
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/task/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * A collection of callable/runnable tasks used to speed up the update process.
- */
-package org.owasp.dependencycheck.data.update.task;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/package-info.java
deleted file mode 100644
index 8dbc168c1..000000000
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/update/xml/package-info.java
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Contains classes used to parse the NVD CVE XML file.
- *
- * The basic use is that the Importer is called to import an NVD CVE file. The Importer instantiates an Indexer object (which
- * extends Index). The Indexer creates a partial-unmarshalling SAX parser (implemented in the NvdCveXmlFilter) that extracts
- * VulnerabilityTypes (aka Entry) from the NVD CVE data file and stores these into a Lucene Index.
- */
-package org.owasp.dependencycheck.data.update.xml;
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java
index d5e744c40..521cff011 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java
@@ -57,8 +57,7 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
/**
*
- * Parses a name attribute value, from the cpe.xml, into its corresponding parts: vendor, product, version,
- * revision.
+ * Parses a name attribute value, from the cpe.xml, into its corresponding parts: vendor, product, version, update.
*
* Example:
* cpe:/a:apache:struts:1.1:rc2
@@ -85,7 +84,7 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
version = urlDecode(data[2]);
}
if (data.length >= 4) {
- revision = urlDecode(data[3]);
+ update = urlDecode(data[3]);
}
if (data.length >= 5) {
edition = urlDecode(data[4]);
@@ -297,26 +296,26 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
this.version = version;
}
/**
- * The product revision version.
+ * The product update version.
*/
- private String revision;
+ private String update;
/**
- * Get the value of revision.
+ * Get the value of update.
*
- * @return the value of revision
+ * @return the value of update
*/
- public String getRevision() {
- return revision;
+ public String getUpdate() {
+ return update;
}
/**
- * Set the value of revision.
+ * Set the value of update.
*
- * @param revision new value of revision
+ * @param update new value of update
*/
- public void setRevision(String revision) {
- this.revision = revision;
+ public void setUpdate(String update) {
+ this.update = update;
}
/**
* The product edition.
@@ -363,11 +362,9 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
}
/**
- * Call {@link java.net.URLDecoder#decode(String)} to URL decode using the
- * default encoding.
+ * Call {@link java.net.URLDecoder#decode(String)} to URL decode using the default encoding.
*
- * @param text
- * www-form-encoded URL to decode
+ * @param text www-form-encoded URL to decode
* @return the newly decoded String
*/
@SuppressWarnings("deprecation")
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DCResources.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DCResources.java
index 4eedc5f36..e0e8a0540 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DCResources.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/DCResources.java
@@ -22,7 +22,7 @@ import ch.qos.cal10n.Locale;
import ch.qos.cal10n.LocaleData;
/**
- * Created by colezlaw on 6/13/15.
+ * @author colezlaw
*/
@BaseName("dependencycheck-resources")
@LocaleData(defaultCharset = "UTF-8",
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java
index a39f01cd5..6aed21164 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java
@@ -17,8 +17,6 @@
*/
package org.owasp.dependencycheck.utils;
-import static org.owasp.dependencycheck.utils.FileUtils.getFileExtension;
-
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
@@ -109,8 +107,7 @@ public final class ExtractionUtil {
}
} else {
final File file = new File(extractTo, entry.getName());
- final String ext = getFileExtension(file.getName());
- if (engine == null || engine.supportsExtension(ext)) {
+ if (engine == null || engine.accept(file)) {
BufferedOutputStream bos = null;
FileOutputStream fos;
try {
@@ -227,7 +224,7 @@ public final class ExtractionUtil {
final File file = new File(destination, entry.getName());
if (filter.accept(file.getParentFile(), file.getName())) {
LOGGER.debug("Extracting '{}'",
- file.getPath());
+ file.getPath());
BufferedOutputStream bos = null;
FileOutputStream fos = null;
try {
@@ -303,5 +300,4 @@ public final class ExtractionUtil {
}
}
}
-
}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java
new file mode 100644
index 000000000..0b9016adc
--- /dev/null
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/FileFilterBuilder.java
@@ -0,0 +1,138 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.utils;
+
+import org.apache.commons.io.IOCase;
+import org.apache.commons.io.filefilter.IOFileFilter;
+import org.apache.commons.io.filefilter.NameFileFilter;
+import org.apache.commons.io.filefilter.OrFileFilter;
+import org.apache.commons.io.filefilter.SuffixFileFilter;
+
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ *
+ * Utility class for building useful {@link FileFilter} instances for
+ * {@link org.owasp.dependencycheck.analyzer.AbstractFileTypeAnalyzer} implementations. The built filter uses {@link OrFileFilter}
+ * to logically OR the given filter conditions. Example usage:
+ *
+ * @author Dale Visser
+ * @see Builder pattern
+ */
+public class FileFilterBuilder {
+
+ /**
+ * A set of filenames to filter.
+ */
+ private final Set filenames = new HashSet();
+ /**
+ * A set of extensions to filter.
+ */
+ private final Set extensions = new HashSet();
+ /**
+ * An array list of file filters.
+ */
+ private final List fileFilters = new ArrayList();
+
+ /**
+ * Create a new instance and return it. This method is for convenience in using the builder pattern within a single statement.
+ *
+ * @return a new builder instance
+ */
+ public static FileFilterBuilder newInstance() {
+ return new FileFilterBuilder();
+ }
+
+ /**
+ * Add to the set of filenames to accept for analysis. Case-sensitivity is assumed.
+ *
+ * @param names one or more filenames to accept for analysis
+ * @return this builder
+ */
+ public FileFilterBuilder addFilenames(String... names) {
+ filenames.addAll(Arrays.asList(names));
+ return this;
+ }
+
+ /**
+ * Add to the set of file extensions to accept for analysis. Case-insensitivity is assumed.
+ *
+ * @param extensions one or more file extensions to accept for analysis
+ * @return this builder
+ */
+ public FileFilterBuilder addExtensions(String... extensions) {
+ return this.addExtensions(Arrays.asList(extensions));
+ }
+
+ /**
+ * Add to the set of file extensions to accept for analysis. Case-insensitivity is assumed.
+ *
+ * @param extensions one or more file extensions to accept for analysis
+ * @return this builder
+ */
+ public FileFilterBuilder addExtensions(Iterable extensions) {
+ for (String extension : extensions) {
+ // Ultimately, SuffixFileFilter will be used, and the "." needs to be explicit.
+ this.extensions.add(extension.startsWith(".") ? extension : "." + extension);
+ }
+ return this;
+ }
+
+ /**
+ * Add to a list of {@link IOFileFilter} instances to consult for whether to accept a file for analysis.
+ *
+ * @param filters one or more file filters to consult for whether to accept for analysis
+ * @return this builder
+ */
+ public FileFilterBuilder addFileFilters(IOFileFilter... filters) {
+ fileFilters.addAll(Arrays.asList(filters));
+ return this;
+ }
+
+ /**
+ * Builds the filter and returns it.
+ *
+ * @return a filter that is the logical OR of all the conditions provided by the add... methods
+ * @throws IllegalStateException if no add... method has been called with one or more arguments
+ */
+ public FileFilter build() {
+ if (filenames.isEmpty() && extensions.isEmpty() && fileFilters.isEmpty()) {
+ throw new IllegalStateException("May only be invoked after at least one add... method has been invoked.");
+ }
+ final OrFileFilter filter = new OrFileFilter();
+ if (!filenames.isEmpty()) {
+ filter.addFileFilter(new NameFileFilter(new ArrayList(filenames)));
+ }
+ if (!extensions.isEmpty()) {
+ filter.addFileFilter(new SuffixFileFilter(new ArrayList(extensions), IOCase.INSENSITIVE));
+ }
+ for (IOFileFilter iof : fileFilters) {
+ filter.addFileFilter(iof);
+ }
+ return filter;
+ }
+}
diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomUtils.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomUtils.java
index 60122969a..f3ea0b0e9 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomUtils.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomUtils.java
@@ -48,8 +48,7 @@ public final class PomUtils {
*
* @param file the pom.xml file
* @return returns a
- * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
- * {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
+ * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM {@link Model} object
*/
public static Model readPom(File file) throws AnalysisException {
Model model = null;
@@ -78,8 +77,7 @@ public final class PomUtils {
* @param path the path to the pom.xml file within the jar file
* @param jar the jar file to extract the pom from
* @return returns a
- * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
- * {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
+ * @throws AnalysisException is thrown if there is an exception extracting or parsing the POM {@link Model} object
*/
public static Model readPom(String path, JarFile jar) throws AnalysisException {
final ZipEntry entry = jar.getEntry(path);
diff --git a/dependency-check-core/src/main/resources/data/dbStatements.properties b/dependency-check-core/src/main/resources/data/dbStatements.properties
index 5245a03f0..e612f259e 100644
--- a/dependency-check-core/src/main/resources/data/dbStatements.properties
+++ b/dependency-check-core/src/main/resources/data/dbStatements.properties
@@ -34,3 +34,6 @@ SELECT_PROPERTY=SELECT id, value FROM properties WHERE id = ?
INSERT_PROPERTY=INSERT INTO properties (id, value) VALUES (?, ?)
UPDATE_PROPERTY=UPDATE properties SET value = ? WHERE id = ?
DELETE_PROPERTY=DELETE FROM properties WHERE id = ?
+
+DELETE_UNUSED_DICT_CPE=DELETE FROM cpeEntry WHERE dictionaryEntry=true AND id NOT IN (SELECT cpeEntryId FROM software)
+ADD_DICT_CPE=MERGE INTO cpeEntry (cpe, vendor, product, dictionaryEntry) KEY(cpe) VALUES(?,?,?,true)
diff --git a/dependency-check-core/src/main/resources/data/upgrade_2.9.sql b/dependency-check-core/src/main/resources/data/upgrade_2.9.sql
new file mode 100644
index 000000000..6c2c3382d
--- /dev/null
+++ b/dependency-check-core/src/main/resources/data/upgrade_2.9.sql
@@ -0,0 +1,7 @@
+
+--the following is not currently used.
+--ALTER TABLE cpeEntry ADD COLUMN IF NOT EXISTS dictionaryEntry BOOLEAN;
+--ALTER TABLE cpeEntry ALTER COLUMN dictionaryEntry SET DEFAULT FALSE;
+--UPDATE cpeEntry SET dictionaryEntry=false;
+
+--UPDATE Properties SET value='3.0' WHERE ID='version';
\ No newline at end of file
diff --git a/dependency-check-core/src/main/resources/dependencycheck.properties b/dependency-check-core/src/main/resources/dependencycheck.properties
index 6bbba2235..89f4c5e83 100644
--- a/dependency-check-core/src/main/resources/dependencycheck.properties
+++ b/dependency-check-core/src/main/resources/dependencycheck.properties
@@ -17,7 +17,7 @@ engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt
# below contains a %s then the data.directory will replace the %s.
data.directory=[JAR]/data
#if the filename has a %s it will be replaced with the current expected version
-data.file_name=cve.%s.h2.db
+data.file_name=dc.h2.db
data.version=2.9
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
@@ -53,6 +53,8 @@ cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
+cpe.validfordays=30
+cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz
# file type analyzer settings:
analyzer.archive.enabled=true
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerIntegrationTest.java
index 38fd60298..abd94ee62 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerIntegrationTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzerIntegrationTest.java
@@ -20,8 +20,7 @@ package org.owasp.dependencycheck.analyzer;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.Engine;
@@ -39,7 +38,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
* Test of getSupportedExtensions method, of class ArchiveAnalyzer.
*/
@Test
- public void testGetSupportedExtensions() {
+ public void testSupportsExtensions() {
ArchiveAnalyzer instance = new ArchiveAnalyzer();
Set expResult = new HashSet();
expResult.add("zip");
@@ -52,8 +51,9 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
expResult.add("tar");
expResult.add("gz");
expResult.add("tgz");
- Set result = instance.getSupportedExtensions();
- assertEquals(expResult, result);
+ for (String ext : expResult) {
+ assertTrue(ext, instance.accept(new File("test." + ext)));
+ }
}
/**
@@ -72,28 +72,9 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
*/
@Test
public void testSupportsExtension() {
- String extension = "7z"; //not supported
+ String extension = "test.7z"; //not supported
ArchiveAnalyzer instance = new ArchiveAnalyzer();
- boolean expResult = false;
- boolean result = instance.supportsExtension(extension);
- assertEquals(expResult, result);
-
- extension = "war"; //supported
- expResult = true;
- result = instance.supportsExtension(extension);
- assertEquals(expResult, result);
-
- extension = "ear"; //supported
- result = instance.supportsExtension(extension);
- assertEquals(expResult, result);
-
- extension = "zip"; //supported
- result = instance.supportsExtension(extension);
- assertEquals(expResult, result);
-
- extension = "nupkg"; //supported
- result = instance.supportsExtension(extension);
- assertEquals(expResult, result);
+ assertFalse(extension, instance.accept(new File(extension)));
}
/**
@@ -129,7 +110,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
public void testAnalyze() throws Exception {
ArchiveAnalyzer instance = new ArchiveAnalyzer();
//trick the analyzer into thinking it is active.
- instance.supportsExtension("ear");
+ instance.accept(new File("test.ear"));
try {
instance.initialize();
File file = BaseTest.getResourceAsFile(this, "daytrader-ear-2.1.7.ear");
@@ -160,7 +141,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
public void testAnalyzeTar() throws Exception {
ArchiveAnalyzer instance = new ArchiveAnalyzer();
//trick the analyzer into thinking it is active so that it will initialize
- instance.supportsExtension("tar");
+ instance.accept(new File("test.tar"));
try {
instance.initialize();
@@ -191,7 +172,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
@Test
public void testAnalyzeTarGz() throws Exception {
ArchiveAnalyzer instance = new ArchiveAnalyzer();
- instance.supportsExtension("zip"); //ensure analyzer is "enabled"
+ instance.accept(new File("zip")); //ensure analyzer is "enabled"
try {
instance.initialize();
@@ -244,7 +225,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
@Test
public void testAnalyzeTgz() throws Exception {
ArchiveAnalyzer instance = new ArchiveAnalyzer();
- instance.supportsExtension("zip"); //ensure analyzer is "enabled"
+ instance.accept(new File("zip")); //ensure analyzer is "enabled"
try {
instance.initialize();
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzerTest.java
index 3333227a3..d67c417fd 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzerTest.java
@@ -58,7 +58,7 @@ public class AssemblyAnalyzerTest extends BaseTest {
public void setUp() throws Exception {
try {
analyzer = new AssemblyAnalyzer();
- analyzer.supportsExtension("dll");
+ analyzer.accept(new File("test.dll")); // trick into "thinking it is active"
analyzer.initialize();
} catch (Exception e) {
if (e.getMessage().contains("Could not execute .NET AssemblyAnalyzer")) {
@@ -155,7 +155,7 @@ public class AssemblyAnalyzerTest extends BaseTest {
System.setProperty(LOG_KEY, "error");
// Have to make a NEW analyzer because during setUp, it would have gotten the correct one
AssemblyAnalyzer aanalyzer = new AssemblyAnalyzer();
- aanalyzer.supportsExtension("dll");
+ aanalyzer.accept(new File("test.dll")); // trick into "thinking it is active"
aanalyzer.initialize();
fail("Expected an AnalysisException");
} catch (AnalysisException ae) {
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzerTest.java
index 6e118e41a..d6f8bb79c 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzerTest.java
@@ -17,13 +17,6 @@
*/
package org.owasp.dependencycheck.analyzer;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -31,6 +24,11 @@ import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
/**
* Unit tests for AutoconfAnalyzer. The test resources under autoconf/ were
* obtained from outside open source software projects. Links to those projects
@@ -164,27 +162,15 @@ public class AutoconfAnalyzerTest extends BaseTest {
}
/**
- * Test of {@link AutoconfAnalyzer#getSupportedExtensions}.
+ * Test of {@link AutoconfAnalyzer#accept(File)}.
*/
@Test
- public void testGetSupportedExtensions() {
- final String[] expected = { "ac", "in", "configure" };
- assertEquals("Supported extensions should just have the following: "
- + StringUtils.join(expected, ", "),
- new HashSet(Arrays.asList(expected)),
- analyzer.getSupportedExtensions());
- }
-
- /**
- * Test of {@link AutoconfAnalyzer#supportsExtension}.
- */
- @Test
- public void testSupportsExtension() {
+ public void testSupportsFileExtension() {
assertTrue("Should support \"ac\" extension.",
- analyzer.supportsExtension("ac"));
+ analyzer.accept(new File("configure.ac")));
assertTrue("Should support \"in\" extension.",
- analyzer.supportsExtension("in"));
+ analyzer.accept(new File("configure.in")));
assertTrue("Should support \"configure\" extension.",
- analyzer.supportsExtension("configure"));
+ analyzer.accept(new File("configure")));
}
}
\ No newline at end of file
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java
index 3625537a3..404d57ece 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/CPEAnalyzerIntegrationTest.java
@@ -149,7 +149,7 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
HintAnalyzer hintAnalyzer = new HintAnalyzer();
JarAnalyzer jarAnalyzer = new JarAnalyzer();
- jarAnalyzer.supportsExtension("jar");
+ jarAnalyzer.accept(new File("test.jar"));//trick analyzer into "thinking it is active"
jarAnalyzer.analyze(struts, null);
hintAnalyzer.analyze(struts, null);
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java
index 6ffebbda1..90f345cd7 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java
@@ -17,19 +17,19 @@
*/
package org.owasp.dependencycheck.analyzer;
-import java.io.File;
-import java.util.HashSet;
-import java.util.Properties;
-import java.util.Set;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
/**
- *
* @author Jeremy Long
*/
public class JarAnalyzerTest extends BaseTest {
@@ -94,13 +94,14 @@ public class JarAnalyzerTest extends BaseTest {
* Test of getSupportedExtensions method, of class JarAnalyzer.
*/
@Test
- public void testGetSupportedExtensions() {
+ public void testAcceptSupportedExtensions() throws Exception {
JarAnalyzer instance = new JarAnalyzer();
- Set expResult = new HashSet();
- expResult.add("jar");
- expResult.add("war");
- Set result = instance.getSupportedExtensions();
- assertEquals(expResult, result);
+ instance.initialize();
+ instance.setEnabled(true);
+ String[] files = {"test.jar", "test.war"};
+ for (String name : files) {
+ assertTrue(name, instance.accept(new File(name)));
+ }
}
/**
@@ -114,16 +115,4 @@ public class JarAnalyzerTest extends BaseTest {
assertEquals(expResult, result);
}
- /**
- * Test of supportsExtension method, of class JarAnalyzer.
- */
- @Test
- public void testSupportsExtension() {
- String extension = "jar";
- JarAnalyzer instance = new JarAnalyzer();
- boolean expResult = true;
- boolean result = instance.supportsExtension(extension);
- assertEquals(expResult, result);
- }
-
}
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java
deleted file mode 100644
index 8daf030ed..000000000
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JavaScriptAnalyzerTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * This file is part of dependency-check-core.
- *
- * 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.
- *
- * Copyright (c) 2014 Jeremy Long. All Rights Reserved.
- */
-package org.owasp.dependencycheck.analyzer;
-
-import java.io.File;
-import java.util.HashSet;
-import java.util.Set;
-import static org.junit.Assert.assertEquals;
-import org.junit.Test;
-import org.owasp.dependencycheck.BaseTest;
-import org.owasp.dependencycheck.Engine;
-import org.owasp.dependencycheck.dependency.Dependency;
-
-/**
- *
- * @author Jeremy Long
- */
-public class JavaScriptAnalyzerTest extends BaseTest {
-
- /**
- * Test of getSupportedExtensions method, of class JavaScriptAnalyzer.
- */
- @Test
- public void testGetSupportedExtensions() {
- JavaScriptAnalyzer instance = new JavaScriptAnalyzer();
- Set expResult = new HashSet();
- expResult.add("js");
- Set result = instance.getSupportedExtensions();
- assertEquals(expResult, result);
- }
-
- /**
- * Test of getName method, of class JavaScriptAnalyzer.
- */
- @Test
- public void testGetName() {
- System.out.println("getName");
- JavaScriptAnalyzer instance = new JavaScriptAnalyzer();
- String expResult = "JavaScript Analyzer";
- String result = instance.getName();
- assertEquals(expResult, result);
- }
-
- /**
- * Test of supportsExtension method, of class JavaScriptAnalyzer.
- */
- @Test
- public void testSupportsExtension() {
- String extension = "js";
- JavaScriptAnalyzer instance = new JavaScriptAnalyzer();
- boolean expResult = true;
- boolean result = instance.supportsExtension(extension);
- assertEquals(expResult, result);
- }
-
- /**
- * Test of getAnalysisPhase method, of class JavaScriptAnalyzer.
- */
- @Test
- public void testGetAnalysisPhase() {
- JavaScriptAnalyzer instance = new JavaScriptAnalyzer();
- AnalysisPhase expResult = AnalysisPhase.INFORMATION_COLLECTION;
- AnalysisPhase result = instance.getAnalysisPhase();
- assertEquals(expResult, result);
- }
-
- /**
- * Test of analyze method, of class JavaScriptAnalyzer.
- */
- @Test
- public void testAnalyze() throws Exception {
- //File jq6 = new File(this.getClass().getClassLoader().getResource("jquery-1.6.2.min.js").getPath());
- File jq6 = BaseTest.getResourceAsFile(this, "jquery-1.6.2.min.js");
- //File jq10 = new File(this.getClass().getClassLoader().getResource("jquery-1.10.2.js").getPath());
- File jq10 = BaseTest.getResourceAsFile(this, "jquery-1.10.2.js");
- //File jq10min = new File(this.getClass().getClassLoader().getResource("jquery-1.10.2.min.js").getPath());
- File jq10min = BaseTest.getResourceAsFile(this, "jquery-1.10.2.min.js");
- Dependency depJQ6 = new Dependency(jq6);
- Dependency depJQ10 = new Dependency(jq10);
- Dependency depJQ10min = new Dependency(jq10min);
- Engine engine = null;
- JavaScriptAnalyzer instance = new JavaScriptAnalyzer();
-
-// assertTrue(depJQ6.getEvidence().size() == 0);
-// assertTrue(depJQ10.getEvidence().size() == 0);
-// assertTrue(depJQ10min.getEvidence().size() == 0);
-//
-// instance.analyze(depJQ6, engine);
-// instance.analyze(depJQ10, engine);
-// instance.analyze(depJQ10min, engine);
-// //TODO improve the assertions
-// assertTrue(depJQ6.getEvidence().size() > 0);
-// assertTrue(depJQ10.getEvidence().size() > 0);
-// assertTrue(depJQ10min.getEvidence().size() > 0);
- }
-
- /**
- * Test of initialize method, of class JavaScriptAnalyzer.
- */
- @Test
- public void testInitialize() throws Exception {
- }
-
- /**
- * Test of close method, of class JavaScriptAnalyzer.
- */
- @Test
- public void testClose() throws Exception {
-
- }
-}
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java
index b993c6159..6d184dd2a 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzerTest.java
@@ -24,6 +24,8 @@ import org.junit.Before;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
+import java.io.File;
+
public class NuspecAnalyzerTest extends BaseTest {
private NuspecAnalyzer instance;
@@ -31,6 +33,7 @@ public class NuspecAnalyzerTest extends BaseTest {
@Before
public void setUp() throws Exception {
instance = new NuspecAnalyzer();
+ instance.initialize();
instance.setEnabled(true);
}
@@ -40,15 +43,9 @@ public class NuspecAnalyzerTest extends BaseTest {
}
@Test
- public void testGetSupportedExtensions() {
- assertTrue(instance.getSupportedExtensions().contains("nuspec"));
- assertFalse(instance.getSupportedExtensions().contains("nupkg"));
- }
-
- @Test
- public void testSupportsExtension() {
- assertTrue(instance.supportsExtension("nuspec"));
- assertFalse(instance.supportsExtension("nupkg"));
+ public void testSupportsFileExtensions() {
+ assertTrue(instance.accept(new File("test.nuspec")));
+ assertFalse(instance.accept(new File("test.nupkg")));
}
@Test
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzerTest.java
index 2a2018884..ded6cb20b 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonDistributionAnalyzerTest.java
@@ -17,13 +17,6 @@
*/
package org.owasp.dependencycheck.analyzer;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -32,6 +25,11 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
/**
* Unit tests for PythonDistributionAnalyzer.
*
@@ -76,33 +74,21 @@ public class PythonDistributionAnalyzerTest extends BaseTest {
analyzer.getName());
}
- /**
- * Test of getSupportedExtensions method, of class PythonDistributionAnalyzer.
- */
- @Test
- public void testGetSupportedExtensions() {
- final String[] expected = {"whl", "egg", "zip", "METADATA", "PKG-INFO"};
- assertEquals("Supported extensions should just have the following: "
- + StringUtils.join(expected, ", "),
- new HashSet(Arrays.asList(expected)),
- analyzer.getSupportedExtensions());
- }
-
/**
* Test of supportsExtension method, of class PythonDistributionAnalyzer.
*/
@Test
- public void testSupportsExtension() {
+ public void testSupportsFiles() {
assertTrue("Should support \"whl\" extension.",
- analyzer.supportsExtension("whl"));
+ analyzer.accept(new File("test.whl")));
assertTrue("Should support \"egg\" extension.",
- analyzer.supportsExtension("egg"));
+ analyzer.accept(new File("test.egg")));
assertTrue("Should support \"zip\" extension.",
- analyzer.supportsExtension("zip"));
+ analyzer.accept(new File("test.zip")));
assertTrue("Should support \"METADATA\" extension.",
- analyzer.supportsExtension("METADATA"));
+ analyzer.accept(new File("METADATA")));
assertTrue("Should support \"PKG-INFO\" extension.",
- analyzer.supportsExtension("PKG-INFO"));
+ analyzer.accept(new File("PKG-INFO")));
}
/**
@@ -119,7 +105,7 @@ public class PythonDistributionAnalyzerTest extends BaseTest {
/**
* Test of inspect method, of class PythonDistributionAnalyzer.
*
- * @throws Exception is thrown when an exception occurs.
+ * @throws AnalysisException is thrown when an exception occurs.
*/
@Test
public void testAnalyzeSitePackage() throws AnalysisException {
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzerTest.java
index d77a8380c..b132c2ec8 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzerTest.java
@@ -17,7 +17,6 @@
*/
package org.owasp.dependencycheck.analyzer;
-import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -26,8 +25,7 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
-import java.util.Arrays;
-import java.util.HashSet;
+import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -76,25 +74,13 @@ public class PythonPackageAnalyzerTest extends BaseTest {
analyzer.getName());
}
- /**
- * Test of getSupportedExtensions method, of class PythonPackageAnalyzer.
- */
- @Test
- public void testGetSupportedExtensions() {
- final String[] expected = {"py"};
- assertEquals("Supported extensions should just have the following: "
- + StringUtils.join(expected, ", "),
- new HashSet(Arrays.asList(expected)),
- analyzer.getSupportedExtensions());
- }
-
/**
* Test of supportsExtension method, of class PythonPackageAnalyzer.
*/
@Test
- public void testSupportsExtension() {
+ public void testSupportsFileExtension() {
assertTrue("Should support \"py\" extension.",
- analyzer.supportsExtension("py"));
+ analyzer.accept(new File("test.py")));
}
@Test
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java
index 242971ff4..76fe5cecd 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/BaseDBTestCase.java
@@ -45,7 +45,7 @@ public abstract class BaseDBTestCase extends BaseTest {
public static void ensureDBExists() throws Exception {
java.io.File dataPath = Settings.getDataDirectory();
- String fileName = String.format(Settings.getString(Settings.KEYS.DB_FILE_NAME), Settings.getString(Settings.KEYS.DB_VERSION));
+ String fileName = Settings.getString(Settings.KEYS.DB_FILE_NAME);
java.io.File dataFile = new File(dataPath, fileName);
if (!dataPath.exists() || !dataFile.exists()) {
dataPath.mkdirs();
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/DatabasePropertiesIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/DatabasePropertiesIntegrationTest.java
index e657f11ab..0d5d4112f 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/DatabasePropertiesIntegrationTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/nvdcve/DatabasePropertiesIntegrationTest.java
@@ -21,7 +21,7 @@ import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
-import org.owasp.dependencycheck.data.update.NvdCveInfo;
+import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
/**
*
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/BaseUpdaterTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/BaseUpdaterTest.java
new file mode 100644
index 000000000..71d00d34e
--- /dev/null
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/BaseUpdaterTest.java
@@ -0,0 +1,98 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2015 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.data.update;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.owasp.dependencycheck.BaseTest;
+import org.owasp.dependencycheck.data.nvdcve.CveDB;
+import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
+
+/**
+ *
+ * @author Jeremy Long
+ */
+public class BaseUpdaterTest extends BaseTest {
+
+ /**
+ * Test of getCveDB method, of class BaseUpdater.
+ */
+ @Test
+ public void testGetCveDB() {
+ BaseUpdater instance = new BaseUpdaterImpl();
+ CveDB expResult = null;
+ CveDB result = instance.getCveDB();
+ assertEquals(expResult, result);
+ }
+
+ /**
+ * Test of getProperties method, of class BaseUpdater.
+ */
+ @Test
+ public void testGetProperties() throws UpdateException {
+ BaseUpdater instance = null;
+ try {
+ instance = new BaseUpdaterImpl();
+ instance.openDataStores();
+
+ DatabaseProperties result = instance.getProperties();
+ assertTrue(result.getProperties().keySet().size() > 1);
+ } finally {
+ if (instance != null) {
+ instance.closeDataStores();
+ }
+ }
+ }
+
+ /**
+ * Test of closeDataStores method, of class BaseUpdater.
+ */
+ @Test
+ public void testCloseDataStores() throws UpdateException {
+ BaseUpdater instance = null;
+ try {
+ instance = new BaseUpdaterImpl();
+ instance.openDataStores();
+ } finally {
+ if (instance != null) {
+ instance.closeDataStores();
+ }
+ }
+ }
+
+ /**
+ * Test of openDataStores method, of class BaseUpdater.
+ */
+ @Test
+ public void testOpenDataStores() throws Exception {
+ BaseUpdater instance = null;
+ try {
+ instance = new BaseUpdaterImpl();
+ instance.openDataStores();
+ } finally {
+ if (instance != null) {
+ instance.closeDataStores();
+ }
+ }
+ }
+
+ public class BaseUpdaterImpl extends BaseUpdater {
+ }
+
+}
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java
new file mode 100644
index 000000000..7d08204bb
--- /dev/null
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/CpeUpdaterIntegrationTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 OWASP.
+ *
+ * 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 org.owasp.dependencycheck.data.update;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.owasp.dependencycheck.BaseTest;
+
+/**
+ *
+ * @author jeremy
+ */
+public class CpeUpdaterIntegrationTest extends BaseTest {
+
+ /**
+ * Test of update method, of class CpeUpdater.
+ */
+ @Test
+ public void testUpdate() throws Exception {
+ //commented out as the current code base does not utilize the CpeU[pdater.
+
+// CpeUpdater instance = new CpeUpdater();
+// instance.update();
+ }
+
+}
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIntegrationTest.java
index 3cf0554e7..8f43f1a09 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIntegrationTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIntegrationTest.java
@@ -17,12 +17,13 @@
*/
package org.owasp.dependencycheck.data.update;
-import java.io.File;
-import java.util.Calendar;
-import org.junit.Before;
+import java.net.MalformedURLException;
+import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
-import org.owasp.dependencycheck.utils.Settings;
+import org.owasp.dependencycheck.data.update.exception.UpdateException;
+import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve;
+import org.owasp.dependencycheck.utils.DownloadFailedException;
/**
*
@@ -30,39 +31,33 @@ import org.owasp.dependencycheck.utils.Settings;
*/
public class NvdCveUpdaterIntegrationTest extends BaseTest {
- @Before
- public void setUp() throws Exception {
- int year = Calendar.getInstance().get(Calendar.YEAR);
- if (year <= 2014) {
- //File f = new File(NvdCveUpdaterIntegrationTest.class.getClassLoader().getResource("nvdcve-2.0-2014.xml").getPath());
- File f = BaseTest.getResourceAsFile(this, "nvdcve-2.0-2014.xml");
- String baseURL = f.toURI().toURL().toString();
- String modified12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-modified.xml");
- String modified20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-modified.xml");
- String full12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-%d.xml");
- String full20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-%d.xml");
-// cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
-// cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
-// cve.startyear=2014
-// cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
-// cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
-
- Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, modified12);
- Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, modified20);
- Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, full12);
- Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, full20);
- Settings.setString(Settings.KEYS.CVE_START_YEAR, "2014");
- } else {
- System.err.println("Consider updating the local data files to make the NvdCveUpdaterIntegrationTest perform faster");
- }
+ public NvdCveUpdater getUpdater() throws MalformedURLException, DownloadFailedException, UpdateException {
+ NvdCveUpdater instance = new NvdCveUpdater();
+ return instance;
}
+// test removed as it is duplicative of the EngineIntegrationTest and the NvdCveUpdaterIntergraionTest
+// /**
+// * Test of update method, of class StandardUpdate.
+// */
+// @Test
+// public void testUpdate() throws Exception {
+// StandardUpdate instance = getStandardUpdateTask();
+// instance.update();
+// //TODO make this an actual test
+// }
/**
- * Test of update method, of class NvdCveUpdater.
+ * Test of updatesNeeded method, of class StandardUpdate.
*/
@Test
- public void testUpdate() throws Exception {
- NvdCveUpdater instance = new NvdCveUpdater();
- instance.update();
+ public void testUpdatesNeeded() throws Exception {
+ NvdCveUpdater instance = getUpdater();
+ try {
+ instance.openDataStores();
+ UpdateableNvdCve result = instance.getUpdatesNeeded();
+ assertNotNull(result);
+ } finally {
+ instance.closeDataStores();
+ }
}
}
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/StandardUpdateIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/StandardUpdateIntegrationTest.java
deleted file mode 100644
index 71516bbaf..000000000
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/StandardUpdateIntegrationTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * This file is part of dependency-check-core.
- *
- * 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.
- *
- * Copyright (c) 2013 Jeremy Long. All Rights Reserved.
- */
-package org.owasp.dependencycheck.data.update;
-
-import java.net.MalformedURLException;
-import static org.junit.Assert.assertNotNull;
-import org.junit.Test;
-import org.owasp.dependencycheck.BaseTest;
-import org.owasp.dependencycheck.data.update.exception.UpdateException;
-import org.owasp.dependencycheck.utils.DownloadFailedException;
-
-/**
- *
- * @author Jeremy Long
- */
-public class StandardUpdateIntegrationTest extends BaseTest {
-
- public StandardUpdate getStandardUpdateTask() throws MalformedURLException, DownloadFailedException, UpdateException {
- StandardUpdate instance = new StandardUpdate();
- return instance;
- }
-
- /**
- * Test of openDataStores method, of class StandardUpdate.
- */
- @Test
- public void testOpenDataStores() throws Exception {
- StandardUpdate instance = getStandardUpdateTask();
- instance.openDataStores();
- instance.closeDataStores();
- }
-
-// test removed as it is duplicative of the EngineIntegrationTest and the NvdCveUpdaterIntergraionTest
-// /**
-// * Test of update method, of class StandardUpdate.
-// */
-// @Test
-// public void testUpdate() throws Exception {
-// StandardUpdate instance = getStandardUpdateTask();
-// instance.update();
-// //TODO make this an actual test
-// }
- /**
- * Test of updatesNeeded method, of class StandardUpdate.
- */
- @Test
- public void testUpdatesNeeded() throws Exception {
- StandardUpdate instance = getStandardUpdateTask();
- UpdateableNvdCve result = instance.updatesNeeded();
- assertNotNull(result);
- }
-}
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/task/DownloadTaskTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/DownloadTaskTest.java
similarity index 89%
rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/task/DownloadTaskTest.java
rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/DownloadTaskTest.java
index bdc676e18..573f0739e 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/task/DownloadTaskTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/DownloadTaskTest.java
@@ -15,8 +15,10 @@
*
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update.task;
+package org.owasp.dependencycheck.data.update.nvd;
+import org.owasp.dependencycheck.data.update.nvd.ProcessTask;
+import org.owasp.dependencycheck.data.update.nvd.DownloadTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import org.junit.After;
@@ -26,7 +28,7 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.owasp.dependencycheck.data.nvdcve.CveDB;
-import org.owasp.dependencycheck.data.update.NvdCveInfo;
+import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
import org.owasp.dependencycheck.utils.Settings;
/**
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveInfoTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfoTest.java
similarity index 95%
rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveInfoTest.java
rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfoTest.java
index 84a5e54fc..81250cd52 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveInfoTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfoTest.java
@@ -15,8 +15,9 @@
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update;
+package org.owasp.dependencycheck.data.update.nvd;
+import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveUpdaterIntegrationTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveUpdaterIntegrationTest.java
new file mode 100644
index 000000000..d93fbce6b
--- /dev/null
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCveUpdaterIntegrationTest.java
@@ -0,0 +1,69 @@
+/*
+ * This file is part of dependency-check-core.
+ *
+ * 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.
+ *
+ * Copyright (c) 2013 Jeremy Long. All Rights Reserved.
+ */
+package org.owasp.dependencycheck.data.update.nvd;
+
+import java.io.File;
+import java.util.Calendar;
+import org.junit.Before;
+import org.junit.Test;
+import org.owasp.dependencycheck.BaseTest;
+import org.owasp.dependencycheck.data.update.NvdCveUpdater;
+import org.owasp.dependencycheck.utils.Settings;
+
+/**
+ *
+ * @author Jeremy Long
+ */
+public class NvdCveUpdaterIntegrationTest extends BaseTest {
+
+ @Before
+ public void setUp() throws Exception {
+ int year = Calendar.getInstance().get(Calendar.YEAR);
+ if (year <= 2014) {
+ //File f = new File(NvdCveUpdaterIntegrationTest.class.getClassLoader().getResource("nvdcve-2.0-2014.xml").getPath());
+ File f = BaseTest.getResourceAsFile(this, "nvdcve-2.0-2014.xml");
+ String baseURL = f.toURI().toURL().toString();
+ String modified12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-modified.xml");
+ String modified20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-modified.xml");
+ String full12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-%d.xml");
+ String full20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-%d.xml");
+// cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
+// cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
+// cve.startyear=2014
+// cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
+// cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
+
+ Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, modified12);
+ Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, modified20);
+ Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, full12);
+ Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, full20);
+ Settings.setString(Settings.KEYS.CVE_START_YEAR, "2014");
+ } else {
+ System.err.println("Consider updating the local data files to make the NvdCveUpdaterIntegrationTest perform faster");
+ }
+ }
+
+ /**
+ * Test of update method, of class NvdCveUpdater.
+ */
+ @Test
+ public void testUpdate() throws Exception {
+ NvdCveUpdater instance = new NvdCveUpdater();
+ instance.update();
+ }
+}
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_1_2_HandlerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_1_2_HandlerTest.java
similarity index 94%
rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_1_2_HandlerTest.java
rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_1_2_HandlerTest.java
index 2ab59b245..fa00e849f 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_1_2_HandlerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_1_2_HandlerTest.java
@@ -15,8 +15,9 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update.xml;
+package org.owasp.dependencycheck.data.update.nvd;
+import org.owasp.dependencycheck.data.update.nvd.NvdCve12Handler;
import java.io.File;
import java.util.List;
import java.util.Map;
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_2_0_HandlerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_2_0_HandlerTest.java
similarity index 94%
rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_2_0_HandlerTest.java
rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_2_0_HandlerTest.java
index 403bd6394..ea1c147ad 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/xml/NvdCve_2_0_HandlerTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/NvdCve_2_0_HandlerTest.java
@@ -15,8 +15,9 @@
*
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update.xml;
+package org.owasp.dependencycheck.data.update.nvd;
+import org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler;
import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/UpdateableNvdCveTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCveTest.java
similarity index 96%
rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/UpdateableNvdCveTest.java
rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCveTest.java
index d8e979321..6aee2790e 100644
--- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/UpdateableNvdCveTest.java
+++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/update/nvd/UpdateableNvdCveTest.java
@@ -15,8 +15,10 @@
*
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
*/
-package org.owasp.dependencycheck.data.update;
+package org.owasp.dependencycheck.data.update.nvd;
+import org.owasp.dependencycheck.data.update.nvd.UpdateableNvdCve;
+import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
diff --git a/dependency-check-core/src/test/resources/dependencycheck.properties b/dependency-check-core/src/test/resources/dependencycheck.properties
index a0a7c8aad..84c3597be 100644
--- a/dependency-check-core/src/test/resources/dependencycheck.properties
+++ b/dependency-check-core/src/test/resources/dependencycheck.properties
@@ -19,7 +19,7 @@ data.directory=[JAR]/data
# if the filename has a %s it will be replaced with the current expected version. For file
# based databases the below filename will be added to the data directory above and then
# if the connection string has a %s it will be replaced by the directory/filename path.
-data.file_name=cve.%s.h2.db
+data.file_name=dc.h2.db
data.version=2.9
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
@@ -60,6 +60,9 @@ cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
+cpe.validfordays=30
+cpe.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-dictionary_v2.3.xml.gz
+
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
analyzer.nexus.enabled=true
diff --git a/dependency-check-core/src/test/resources/jquery-1.10.2.js b/dependency-check-core/src/test/resources/jquery-1.10.2.js
deleted file mode 100644
index c5c648255..000000000
--- a/dependency-check-core/src/test/resources/jquery-1.10.2.js
+++ /dev/null
@@ -1,9789 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.10.2
- * http://jquery.com/
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- *
- * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2013-07-03T13:48Z
- */
-(function( window, undefined ) {
-
-// Can't do this because several apps including ASP.NET trace
-// the stack via arguments.caller.callee and Firefox dies if
-// you try to trace through "use strict" call chains. (#13335)
-// Support: Firefox 18+
-//"use strict";
-var
- // The deferred used on DOM ready
- readyList,
-
- // A central reference to the root jQuery(document)
- rootjQuery,
-
- // Support: IE<10
- // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
- core_strundefined = typeof undefined,
-
- // Use the correct document accordingly with window argument (sandbox)
- location = window.location,
- document = window.document,
- docElem = document.documentElement,
-
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
-
- // Map over the $ in case of overwrite
- _$ = window.$,
-
- // [[Class]] -> type pairs
- class2type = {},
-
- // List of deleted data cache ids, so we can reuse them
- core_deletedIds = [],
-
- core_version = "1.10.2",
-
- // Save a reference to some core methods
- core_concat = core_deletedIds.concat,
- core_push = core_deletedIds.push,
- core_slice = core_deletedIds.slice,
- core_indexOf = core_deletedIds.indexOf,
- core_toString = class2type.toString,
- core_hasOwn = class2type.hasOwnProperty,
- core_trim = core_version.trim,
-
- // Define a local copy of jQuery
- jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init( selector, context, rootjQuery );
- },
-
- // Used for matching numbers
- core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
-
- // Used for splitting on whitespace
- core_rnotwhite = /\S+/g,
-
- // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
- rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
-
- // A simple way to check for HTML strings
- // Prioritize #id over to avoid XSS via location.hash (#9521)
- // Strict HTML recognition (#11290: must start with <)
- rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
-
- // Match a standalone tag
- rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
-
- // JSON RegExp
- rvalidchars = /^[\],:{}\s]*$/,
- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
- rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
- rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
-
- // Matches dashed string for camelizing
- rmsPrefix = /^-ms-/,
- rdashAlpha = /-([\da-z])/gi,
-
- // Used by jQuery.camelCase as callback to replace()
- fcamelCase = function( all, letter ) {
- return letter.toUpperCase();
- },
-
- // The ready event handler
- completed = function( event ) {
-
- // readyState === "complete" is good enough for us to call the dom ready in oldIE
- if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
- detach();
- jQuery.ready();
- }
- },
- // Clean-up method for dom ready events
- detach = function() {
- if ( document.addEventListener ) {
- document.removeEventListener( "DOMContentLoaded", completed, false );
- window.removeEventListener( "load", completed, false );
-
- } else {
- document.detachEvent( "onreadystatechange", completed );
- window.detachEvent( "onload", completed );
- }
- };
-
-jQuery.fn = jQuery.prototype = {
- // The current version of jQuery being used
- jquery: core_version,
-
- constructor: jQuery,
- init: function( selector, context, rootjQuery ) {
- var match, elem;
-
- // HANDLE: $(""), $(null), $(undefined), $(false)
- if ( !selector ) {
- return this;
- }
-
- // Handle HTML strings
- if ( typeof selector === "string" ) {
- if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
- // Assume that strings that start and end with <> are HTML and skip the regex check
- match = [ null, selector, null ];
-
- } else {
- match = rquickExpr.exec( selector );
- }
-
- // Match html or make sure no context is specified for #id
- if ( match && (match[1] || !context) ) {
-
- // HANDLE: $(html) -> $(array)
- if ( match[1] ) {
- context = context instanceof jQuery ? context[0] : context;
-
- // scripts is true for back-compat
- jQuery.merge( this, jQuery.parseHTML(
- match[1],
- context && context.nodeType ? context.ownerDocument || context : document,
- true
- ) );
-
- // HANDLE: $(html, props)
- if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
- for ( match in context ) {
- // Properties of context are called as methods if possible
- if ( jQuery.isFunction( this[ match ] ) ) {
- this[ match ]( context[ match ] );
-
- // ...and otherwise set as attributes
- } else {
- this.attr( match, context[ match ] );
- }
- }
- }
-
- return this;
-
- // HANDLE: $(#id)
- } else {
- elem = document.getElementById( match[2] );
-
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id !== match[2] ) {
- return rootjQuery.find( selector );
- }
-
- // Otherwise, we inject the element directly into the jQuery object
- this.length = 1;
- this[0] = elem;
- }
-
- this.context = document;
- this.selector = selector;
- return this;
- }
-
- // HANDLE: $(expr, $(...))
- } else if ( !context || context.jquery ) {
- return ( context || rootjQuery ).find( selector );
-
- // HANDLE: $(expr, context)
- // (which is just equivalent to: $(context).find(expr)
- } else {
- return this.constructor( context ).find( selector );
- }
-
- // HANDLE: $(DOMElement)
- } else if ( selector.nodeType ) {
- this.context = this[0] = selector;
- this.length = 1;
- return this;
-
- // HANDLE: $(function)
- // Shortcut for document ready
- } else if ( jQuery.isFunction( selector ) ) {
- return rootjQuery.ready( selector );
- }
-
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
-
- return jQuery.makeArray( selector, this );
- },
-
- // Start with an empty selector
- selector: "",
-
- // The default length of a jQuery object is 0
- length: 0,
-
- toArray: function() {
- return core_slice.call( this );
- },
-
- // Get the Nth element in the matched element set OR
- // Get the whole matched element set as a clean array
- get: function( num ) {
- return num == null ?
-
- // Return a 'clean' array
- this.toArray() :
-
- // Return just the object
- ( num < 0 ? this[ this.length + num ] : this[ num ] );
- },
-
- // Take an array of elements and push it onto the stack
- // (returning the new matched element set)
- pushStack: function( elems ) {
-
- // Build a new jQuery matched element set
- var ret = jQuery.merge( this.constructor(), elems );
-
- // Add the old object onto the stack (as a reference)
- ret.prevObject = this;
- ret.context = this.context;
-
- // Return the newly-formed element set
- return ret;
- },
-
- // Execute a callback for every element in the matched set.
- // (You can seed the arguments with an array of args, but this is
- // only used internally.)
- each: function( callback, args ) {
- return jQuery.each( this, callback, args );
- },
-
- ready: function( fn ) {
- // Add the callback
- jQuery.ready.promise().done( fn );
-
- return this;
- },
-
- slice: function() {
- return this.pushStack( core_slice.apply( this, arguments ) );
- },
-
- first: function() {
- return this.eq( 0 );
- },
-
- last: function() {
- return this.eq( -1 );
- },
-
- eq: function( i ) {
- var len = this.length,
- j = +i + ( i < 0 ? len : 0 );
- return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
- },
-
- map: function( callback ) {
- return this.pushStack( jQuery.map(this, function( elem, i ) {
- return callback.call( elem, i, elem );
- }));
- },
-
- end: function() {
- return this.prevObject || this.constructor(null);
- },
-
- // For internal use only.
- // Behaves like an Array's method, not like a jQuery method.
- push: core_push,
- sort: [].sort,
- splice: [].splice
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-jQuery.extend = jQuery.fn.extend = function() {
- var src, copyIsArray, copy, name, options, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false;
-
- // Handle a deep copy situation
- if ( typeof target === "boolean" ) {
- deep = target;
- target = arguments[1] || {};
- // skip the boolean and the target
- i = 2;
- }
-
- // Handle case when target is a string or something (possible in deep copy)
- if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
- target = {};
- }
-
- // extend jQuery itself if only one argument is passed
- if ( length === i ) {
- target = this;
- --i;
- }
-
- for ( ; i < length; i++ ) {
- // Only deal with non-null/undefined values
- if ( (options = arguments[ i ]) != null ) {
- // Extend the base object
- for ( name in options ) {
- src = target[ name ];
- copy = options[ name ];
-
- // Prevent never-ending loop
- if ( target === copy ) {
- continue;
- }
-
- // Recurse if we're merging plain objects or arrays
- if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
- if ( copyIsArray ) {
- copyIsArray = false;
- clone = src && jQuery.isArray(src) ? src : [];
-
- } else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
- }
-
- // Never move original objects, clone them
- target[ name ] = jQuery.extend( deep, clone, copy );
-
- // Don't bring in undefined values
- } else if ( copy !== undefined ) {
- target[ name ] = copy;
- }
- }
- }
- }
-
- // Return the modified object
- return target;
-};
-
-jQuery.extend({
- // Unique for each copy of jQuery on the page
- // Non-digits removed to match rinlinejQuery
- expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
-
- noConflict: function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
-
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
-
- return jQuery;
- },
-
- // Is the DOM ready to be used? Set to true once it occurs.
- isReady: false,
-
- // A counter to track how many items to wait for before
- // the ready event fires. See #6781
- readyWait: 1,
-
- // Hold (or release) the ready event
- holdReady: function( hold ) {
- if ( hold ) {
- jQuery.readyWait++;
- } else {
- jQuery.ready( true );
- }
- },
-
- // Handle when the DOM is ready
- ready: function( wait ) {
-
- // Abort if there are pending holds or we're already ready
- if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
- return;
- }
-
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( !document.body ) {
- return setTimeout( jQuery.ready );
- }
-
- // Remember that the DOM is ready
- jQuery.isReady = true;
-
- // If a normal DOM Ready event fired, decrement, and wait if need be
- if ( wait !== true && --jQuery.readyWait > 0 ) {
- return;
- }
-
- // If there are functions bound, to execute
- readyList.resolveWith( document, [ jQuery ] );
-
- // Trigger any bound ready events
- if ( jQuery.fn.trigger ) {
- jQuery( document ).trigger("ready").off("ready");
- }
- },
-
- // See test/unit/core.js for details concerning isFunction.
- // Since version 1.3, DOM methods and functions like alert
- // aren't supported. They return false on IE (#2968).
- isFunction: function( obj ) {
- return jQuery.type(obj) === "function";
- },
-
- isArray: Array.isArray || function( obj ) {
- return jQuery.type(obj) === "array";
- },
-
- isWindow: function( obj ) {
- /* jshint eqeqeq: false */
- return obj != null && obj == obj.window;
- },
-
- isNumeric: function( obj ) {
- return !isNaN( parseFloat(obj) ) && isFinite( obj );
- },
-
- type: function( obj ) {
- if ( obj == null ) {
- return String( obj );
- }
- return typeof obj === "object" || typeof obj === "function" ?
- class2type[ core_toString.call(obj) ] || "object" :
- typeof obj;
- },
-
- isPlainObject: function( obj ) {
- var key;
-
- // Must be an Object.
- // Because of IE, we also have to check the presence of the constructor property.
- // Make sure that DOM nodes and window objects don't pass through, as well
- if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
- return false;
- }
-
- try {
- // Not own constructor property must be Object
- if ( obj.constructor &&
- !core_hasOwn.call(obj, "constructor") &&
- !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
- } catch ( e ) {
- // IE8,9 Will throw exceptions on certain host objects #9897
- return false;
- }
-
- // Support: IE<9
- // Handle iteration over inherited properties before own properties.
- if ( jQuery.support.ownLast ) {
- for ( key in obj ) {
- return core_hasOwn.call( obj, key );
- }
- }
-
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
- for ( key in obj ) {}
-
- return key === undefined || core_hasOwn.call( obj, key );
- },
-
- isEmptyObject: function( obj ) {
- var name;
- for ( name in obj ) {
- return false;
- }
- return true;
- },
-
- error: function( msg ) {
- throw new Error( msg );
- },
-
- // data: string of html
- // context (optional): If specified, the fragment will be created in this context, defaults to document
- // keepScripts (optional): If true, will include scripts passed in the html string
- parseHTML: function( data, context, keepScripts ) {
- if ( !data || typeof data !== "string" ) {
- return null;
- }
- if ( typeof context === "boolean" ) {
- keepScripts = context;
- context = false;
- }
- context = context || document;
-
- var parsed = rsingleTag.exec( data ),
- scripts = !keepScripts && [];
-
- // Single tag
- if ( parsed ) {
- return [ context.createElement( parsed[1] ) ];
- }
-
- parsed = jQuery.buildFragment( [ data ], context, scripts );
- if ( scripts ) {
- jQuery( scripts ).remove();
- }
- return jQuery.merge( [], parsed.childNodes );
- },
-
- parseJSON: function( data ) {
- // Attempt to parse using the native JSON parser first
- if ( window.JSON && window.JSON.parse ) {
- return window.JSON.parse( data );
- }
-
- if ( data === null ) {
- return data;
- }
-
- if ( typeof data === "string" ) {
-
- // Make sure leading/trailing whitespace is removed (IE can't handle it)
- data = jQuery.trim( data );
-
- if ( data ) {
- // Make sure the incoming data is actual JSON
- // Logic borrowed from http://json.org/json2.js
- if ( rvalidchars.test( data.replace( rvalidescape, "@" )
- .replace( rvalidtokens, "]" )
- .replace( rvalidbraces, "")) ) {
-
- return ( new Function( "return " + data ) )();
- }
- }
- }
-
- jQuery.error( "Invalid JSON: " + data );
- },
-
- // Cross-browser xml parsing
- parseXML: function( data ) {
- var xml, tmp;
- if ( !data || typeof data !== "string" ) {
- return null;
- }
- try {
- if ( window.DOMParser ) { // Standard
- tmp = new DOMParser();
- xml = tmp.parseFromString( data , "text/xml" );
- } else { // IE
- xml = new ActiveXObject( "Microsoft.XMLDOM" );
- xml.async = "false";
- xml.loadXML( data );
- }
- } catch( e ) {
- xml = undefined;
- }
- if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
- jQuery.error( "Invalid XML: " + data );
- }
- return xml;
- },
-
- noop: function() {},
-
- // Evaluates a script in a global context
- // Workarounds based on findings by Jim Driscoll
- // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
- globalEval: function( data ) {
- if ( data && jQuery.trim( data ) ) {
- // We use execScript on Internet Explorer
- // We use an anonymous function so that context is window
- // rather than jQuery in Firefox
- ( window.execScript || function( data ) {
- window[ "eval" ].call( window, data );
- } )( data );
- }
- },
-
- // Convert dashed to camelCase; used by the css and data modules
- // Microsoft forgot to hump their vendor prefix (#9572)
- camelCase: function( string ) {
- return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
- },
-
- nodeName: function( elem, name ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
- },
-
- // args is for internal usage only
- each: function( obj, callback, args ) {
- var value,
- i = 0,
- length = obj.length,
- isArray = isArraylike( obj );
-
- if ( args ) {
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback.apply( obj[ i ], args );
-
- if ( value === false ) {
- break;
- }
- }
- } else {
- for ( i in obj ) {
- value = callback.apply( obj[ i ], args );
-
- if ( value === false ) {
- break;
- }
- }
- }
-
- // A special, fast, case for the most common use of each
- } else {
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback.call( obj[ i ], i, obj[ i ] );
-
- if ( value === false ) {
- break;
- }
- }
- } else {
- for ( i in obj ) {
- value = callback.call( obj[ i ], i, obj[ i ] );
-
- if ( value === false ) {
- break;
- }
- }
- }
- }
-
- return obj;
- },
-
- // Use native String.trim function wherever possible
- trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
- function( text ) {
- return text == null ?
- "" :
- core_trim.call( text );
- } :
-
- // Otherwise use our own trimming functionality
- function( text ) {
- return text == null ?
- "" :
- ( text + "" ).replace( rtrim, "" );
- },
-
- // results is for internal usage only
- makeArray: function( arr, results ) {
- var ret = results || [];
-
- if ( arr != null ) {
- if ( isArraylike( Object(arr) ) ) {
- jQuery.merge( ret,
- typeof arr === "string" ?
- [ arr ] : arr
- );
- } else {
- core_push.call( ret, arr );
- }
- }
-
- return ret;
- },
-
- inArray: function( elem, arr, i ) {
- var len;
-
- if ( arr ) {
- if ( core_indexOf ) {
- return core_indexOf.call( arr, elem, i );
- }
-
- len = arr.length;
- i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
-
- for ( ; i < len; i++ ) {
- // Skip accessing in sparse arrays
- if ( i in arr && arr[ i ] === elem ) {
- return i;
- }
- }
- }
-
- return -1;
- },
-
- merge: function( first, second ) {
- var l = second.length,
- i = first.length,
- j = 0;
-
- if ( typeof l === "number" ) {
- for ( ; j < l; j++ ) {
- first[ i++ ] = second[ j ];
- }
- } else {
- while ( second[j] !== undefined ) {
- first[ i++ ] = second[ j++ ];
- }
- }
-
- first.length = i;
-
- return first;
- },
-
- grep: function( elems, callback, inv ) {
- var retVal,
- ret = [],
- i = 0,
- length = elems.length;
- inv = !!inv;
-
- // Go through the array, only saving the items
- // that pass the validator function
- for ( ; i < length; i++ ) {
- retVal = !!callback( elems[ i ], i );
- if ( inv !== retVal ) {
- ret.push( elems[ i ] );
- }
- }
-
- return ret;
- },
-
- // arg is for internal usage only
- map: function( elems, callback, arg ) {
- var value,
- i = 0,
- length = elems.length,
- isArray = isArraylike( elems ),
- ret = [];
-
- // Go through the array, translating each of the items to their
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
-
- // Go through every key on the object,
- } else {
- for ( i in elems ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
- }
-
- // Flatten any nested arrays
- return core_concat.apply( [], ret );
- },
-
- // A global GUID counter for objects
- guid: 1,
-
- // Bind a function to a context, optionally partially applying any
- // arguments.
- proxy: function( fn, context ) {
- var args, proxy, tmp;
-
- if ( typeof context === "string" ) {
- tmp = fn[ context ];
- context = fn;
- fn = tmp;
- }
-
- // Quick check to determine if target is callable, in the spec
- // this throws a TypeError, but we will just return undefined.
- if ( !jQuery.isFunction( fn ) ) {
- return undefined;
- }
-
- // Simulated bind
- args = core_slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
- };
-
- // Set the guid of unique handler to the same of original handler, so it can be removed
- proxy.guid = fn.guid = fn.guid || jQuery.guid++;
-
- return proxy;
- },
-
- // Multifunctional method to get and set values of a collection
- // The value/s can optionally be executed if it's a function
- access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
- var i = 0,
- length = elems.length,
- bulk = key == null;
-
- // Sets many values
- if ( jQuery.type( key ) === "object" ) {
- chainable = true;
- for ( i in key ) {
- jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
- }
-
- // Sets one value
- } else if ( value !== undefined ) {
- chainable = true;
-
- if ( !jQuery.isFunction( value ) ) {
- raw = true;
- }
-
- if ( bulk ) {
- // Bulk operations run against the entire set
- if ( raw ) {
- fn.call( elems, value );
- fn = null;
-
- // ...except when executing function values
- } else {
- bulk = fn;
- fn = function( elem, key, value ) {
- return bulk.call( jQuery( elem ), value );
- };
- }
- }
-
- if ( fn ) {
- for ( ; i < length; i++ ) {
- fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
- }
- }
- }
-
- return chainable ?
- elems :
-
- // Gets
- bulk ?
- fn.call( elems ) :
- length ? fn( elems[0], key ) : emptyGet;
- },
-
- now: function() {
- return ( new Date() ).getTime();
- },
-
- // A method for quickly swapping in/out CSS properties to get correct calculations.
- // Note: this method belongs to the css module but it's needed here for the support module.
- // If support gets modularized, this method should be moved back to the css module.
- swap: function( elem, options, callback, args ) {
- var ret, name,
- old = {};
-
- // Remember the old values, and insert the new ones
- for ( name in options ) {
- old[ name ] = elem.style[ name ];
- elem.style[ name ] = options[ name ];
- }
-
- ret = callback.apply( elem, args || [] );
-
- // Revert the old values
- for ( name in options ) {
- elem.style[ name ] = old[ name ];
- }
-
- return ret;
- }
-});
-
-jQuery.ready.promise = function( obj ) {
- if ( !readyList ) {
-
- readyList = jQuery.Deferred();
-
- // Catch cases where $(document).ready() is called after the browser event has already occurred.
- // we once tried to use readyState "interactive" here, but it caused issues like the one
- // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
- if ( document.readyState === "complete" ) {
- // Handle it asynchronously to allow scripts the opportunity to delay ready
- setTimeout( jQuery.ready );
-
- // Standards-based browsers support DOMContentLoaded
- } else if ( document.addEventListener ) {
- // Use the handy event callback
- document.addEventListener( "DOMContentLoaded", completed, false );
-
- // A fallback to window.onload, that will always work
- window.addEventListener( "load", completed, false );
-
- // If IE event model is used
- } else {
- // Ensure firing before onload, maybe late but safe also for iframes
- document.attachEvent( "onreadystatechange", completed );
-
- // A fallback to window.onload, that will always work
- window.attachEvent( "onload", completed );
-
- // If IE and not a frame
- // continually check to see if the document is ready
- var top = false;
-
- try {
- top = window.frameElement == null && document.documentElement;
- } catch(e) {}
-
- if ( top && top.doScroll ) {
- (function doScrollCheck() {
- if ( !jQuery.isReady ) {
-
- try {
- // Use the trick by Diego Perini
- // http://javascript.nwbox.com/IEContentLoaded/
- top.doScroll("left");
- } catch(e) {
- return setTimeout( doScrollCheck, 50 );
- }
-
- // detach all dom ready events
- detach();
-
- // and execute any waiting functions
- jQuery.ready();
- }
- })();
- }
- }
- }
- return readyList.promise( obj );
-};
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
- class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-function isArraylike( obj ) {
- var length = obj.length,
- type = jQuery.type( obj );
-
- if ( jQuery.isWindow( obj ) ) {
- return false;
- }
-
- if ( obj.nodeType === 1 && length ) {
- return true;
- }
-
- return type === "array" || type !== "function" &&
- ( length === 0 ||
- typeof length === "number" && length > 0 && ( length - 1 ) in obj );
-}
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-/*!
- * Sizzle CSS Selector Engine v1.10.2
- * http://sizzlejs.com/
- *
- * Copyright 2013 jQuery Foundation, Inc. and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2013-07-03
- */
-(function( window, undefined ) {
-
-var i,
- support,
- cachedruns,
- Expr,
- getText,
- isXML,
- compile,
- outermostContext,
- sortInput,
-
- // Local document vars
- setDocument,
- document,
- docElem,
- documentIsHTML,
- rbuggyQSA,
- rbuggyMatches,
- matches,
- contains,
-
- // Instance-specific data
- expando = "sizzle" + -(new Date()),
- preferredDoc = window.document,
- dirruns = 0,
- done = 0,
- classCache = createCache(),
- tokenCache = createCache(),
- compilerCache = createCache(),
- hasDuplicate = false,
- sortOrder = function( a, b ) {
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
- return 0;
- },
-
- // General-purpose constants
- strundefined = typeof undefined,
- MAX_NEGATIVE = 1 << 31,
-
- // Instance methods
- hasOwn = ({}).hasOwnProperty,
- arr = [],
- pop = arr.pop,
- push_native = arr.push,
- push = arr.push,
- slice = arr.slice,
- // Use a stripped-down indexOf if we can't use a native one
- indexOf = arr.indexOf || function( elem ) {
- var i = 0,
- len = this.length;
- for ( ; i < len; i++ ) {
- if ( this[i] === elem ) {
- return i;
- }
- }
- return -1;
- },
-
- booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
-
- // Regular expressions
-
- // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
- whitespace = "[\\x20\\t\\r\\n\\f]",
- // http://www.w3.org/TR/css3-syntax/#characters
- characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
-
- // Loosely modeled on CSS identifier characters
- // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
- // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
- identifier = characterEncoding.replace( "w", "w#" ),
-
- // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
- attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
- "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
-
- // Prefer arguments quoted,
- // then not containing pseudos/brackets,
- // then attribute selectors/non-parenthetical expressions,
- // then anything else
- // These preferences are here to reduce the number of selectors
- // needing tokenize in the PSEUDO preFilter
- pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
-
- // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
- rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
-
- rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
- rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
-
- rsibling = new RegExp( whitespace + "*[+~]" ),
- rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
-
- rpseudo = new RegExp( pseudos ),
- ridentifier = new RegExp( "^" + identifier + "$" ),
-
- matchExpr = {
- "ID": new RegExp( "^#(" + characterEncoding + ")" ),
- "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
- "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
- "ATTR": new RegExp( "^" + attributes ),
- "PSEUDO": new RegExp( "^" + pseudos ),
- "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
- "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
- "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
- "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
- // For use in libraries implementing .is()
- // We use this for POS matching in `select`
- "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
- whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
- },
-
- rnative = /^[^{]+\{\s*\[native \w/,
-
- // Easily-parseable/retrievable ID or TAG or CLASS selectors
- rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
-
- rinputs = /^(?:input|select|textarea|button)$/i,
- rheader = /^h\d$/i,
-
- rescape = /'|\\/g,
-
- // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
- runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
- funescape = function( _, escaped, escapedWhitespace ) {
- var high = "0x" + escaped - 0x10000;
- // NaN means non-codepoint
- // Support: Firefox
- // Workaround erroneous numeric interpretation of +"0x"
- return high !== high || escapedWhitespace ?
- escaped :
- // BMP codepoint
- high < 0 ?
- String.fromCharCode( high + 0x10000 ) :
- // Supplemental Plane codepoint (surrogate pair)
- String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
- };
-
-// Optimize for push.apply( _, NodeList )
-try {
- push.apply(
- (arr = slice.call( preferredDoc.childNodes )),
- preferredDoc.childNodes
- );
- // Support: Android<4.0
- // Detect silently failing push.apply
- arr[ preferredDoc.childNodes.length ].nodeType;
-} catch ( e ) {
- push = { apply: arr.length ?
-
- // Leverage slice if possible
- function( target, els ) {
- push_native.apply( target, slice.call(els) );
- } :
-
- // Support: IE<9
- // Otherwise append directly
- function( target, els ) {
- var j = target.length,
- i = 0;
- // Can't trust NodeList.length
- while ( (target[j++] = els[i++]) ) {}
- target.length = j - 1;
- }
- };
-}
-
-function Sizzle( selector, context, results, seed ) {
- var match, elem, m, nodeType,
- // QSA vars
- i, groups, old, nid, newContext, newSelector;
-
- if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
- setDocument( context );
- }
-
- context = context || document;
- results = results || [];
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
- return [];
- }
-
- if ( documentIsHTML && !seed ) {
-
- // Shortcuts
- if ( (match = rquickExpr.exec( selector )) ) {
- // Speed-up: Sizzle("#ID")
- if ( (m = match[1]) ) {
- if ( nodeType === 9 ) {
- elem = context.getElementById( m );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE, Opera, and Webkit return items
- // by name instead of ID
- if ( elem.id === m ) {
- results.push( elem );
- return results;
- }
- } else {
- return results;
- }
- } else {
- // Context is not a document
- if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
- contains( context, elem ) && elem.id === m ) {
- results.push( elem );
- return results;
- }
- }
-
- // Speed-up: Sizzle("TAG")
- } else if ( match[2] ) {
- push.apply( results, context.getElementsByTagName( selector ) );
- return results;
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
- push.apply( results, context.getElementsByClassName( m ) );
- return results;
- }
- }
-
- // QSA path
- if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
- nid = old = expando;
- newContext = context;
- newSelector = nodeType === 9 && selector;
-
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- groups = tokenize( selector );
-
- if ( (old = context.getAttribute("id")) ) {
- nid = old.replace( rescape, "\\$&" );
- } else {
- context.setAttribute( "id", nid );
- }
- nid = "[id='" + nid + "'] ";
-
- i = groups.length;
- while ( i-- ) {
- groups[i] = nid + toSelector( groups[i] );
- }
- newContext = rsibling.test( selector ) && context.parentNode || context;
- newSelector = groups.join(",");
- }
-
- if ( newSelector ) {
- try {
- push.apply( results,
- newContext.querySelectorAll( newSelector )
- );
- return results;
- } catch(qsaError) {
- } finally {
- if ( !old ) {
- context.removeAttribute("id");
- }
- }
- }
- }
- }
-
- // All others
- return select( selector.replace( rtrim, "$1" ), context, results, seed );
-}
-
-/**
- * Create key-value caches of limited size
- * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
- * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
- * deleting the oldest entry
- */
-function createCache() {
- var keys = [];
-
- function cache( key, value ) {
- // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
- if ( keys.push( key += " " ) > Expr.cacheLength ) {
- // Only keep the most recent entries
- delete cache[ keys.shift() ];
- }
- return (cache[ key ] = value);
- }
- return cache;
-}
-
-/**
- * Mark a function for special use by Sizzle
- * @param {Function} fn The function to mark
- */
-function markFunction( fn ) {
- fn[ expando ] = true;
- return fn;
-}
-
-/**
- * Support testing using an element
- * @param {Function} fn Passed the created div and expects a boolean result
- */
-function assert( fn ) {
- var div = document.createElement("div");
-
- try {
- return !!fn( div );
- } catch (e) {
- return false;
- } finally {
- // Remove from its parent by default
- if ( div.parentNode ) {
- div.parentNode.removeChild( div );
- }
- // release memory in IE
- div = null;
- }
-}
-
-/**
- * Adds the same handler for all of the specified attrs
- * @param {String} attrs Pipe-separated list of attributes
- * @param {Function} handler The method that will be applied
- */
-function addHandle( attrs, handler ) {
- var arr = attrs.split("|"),
- i = attrs.length;
-
- while ( i-- ) {
- Expr.attrHandle[ arr[i] ] = handler;
- }
-}
-
-/**
- * Checks document order of two siblings
- * @param {Element} a
- * @param {Element} b
- * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
- */
-function siblingCheck( a, b ) {
- var cur = b && a,
- diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
- ( ~b.sourceIndex || MAX_NEGATIVE ) -
- ( ~a.sourceIndex || MAX_NEGATIVE );
-
- // Use IE sourceIndex if available on both nodes
- if ( diff ) {
- return diff;
- }
-
- // Check if b follows a
- if ( cur ) {
- while ( (cur = cur.nextSibling) ) {
- if ( cur === b ) {
- return -1;
- }
- }
- }
-
- return a ? 1 : -1;
-}
-
-/**
- * Returns a function to use in pseudos for input types
- * @param {String} type
- */
-function createInputPseudo( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === type;
- };
-}
-
-/**
- * Returns a function to use in pseudos for buttons
- * @param {String} type
- */
-function createButtonPseudo( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && elem.type === type;
- };
-}
-
-/**
- * Returns a function to use in pseudos for positionals
- * @param {Function} fn
- */
-function createPositionalPseudo( fn ) {
- return markFunction(function( argument ) {
- argument = +argument;
- return markFunction(function( seed, matches ) {
- var j,
- matchIndexes = fn( [], seed.length, argument ),
- i = matchIndexes.length;
-
- // Match elements found at the specified indexes
- while ( i-- ) {
- if ( seed[ (j = matchIndexes[i]) ] ) {
- seed[j] = !(matches[j] = seed[j]);
- }
- }
- });
- });
-}
-
-/**
- * Detect xml
- * @param {Element|Object} elem An element or a document
- */
-isXML = Sizzle.isXML = function( elem ) {
- // documentElement is verified for cases where it doesn't yet exist
- // (such as loading iframes in IE - #4833)
- var documentElement = elem && (elem.ownerDocument || elem).documentElement;
- return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-// Expose support vars for convenience
-support = Sizzle.support = {};
-
-/**
- * Sets document-related variables once based on the current document
- * @param {Element|Object} [doc] An element or document object to use to set the document
- * @returns {Object} Returns the current document
- */
-setDocument = Sizzle.setDocument = function( node ) {
- var doc = node ? node.ownerDocument || node : preferredDoc,
- parent = doc.defaultView;
-
- // If no document and documentElement is available, return
- if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
- return document;
- }
-
- // Set our document
- document = doc;
- docElem = doc.documentElement;
-
- // Support tests
- documentIsHTML = !isXML( doc );
-
- // Support: IE>8
- // If iframe document is assigned to "document" variable and if iframe has been reloaded,
- // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
- // IE6-8 do not support the defaultView property so parent will be undefined
- if ( parent && parent.attachEvent && parent !== parent.top ) {
- parent.attachEvent( "onbeforeunload", function() {
- setDocument();
- });
- }
-
- /* Attributes
- ---------------------------------------------------------------------- */
-
- // Support: IE<8
- // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
- support.attributes = assert(function( div ) {
- div.className = "i";
- return !div.getAttribute("className");
- });
-
- /* getElement(s)By*
- ---------------------------------------------------------------------- */
-
- // Check if getElementsByTagName("*") returns only elements
- support.getElementsByTagName = assert(function( div ) {
- div.appendChild( doc.createComment("") );
- return !div.getElementsByTagName("*").length;
- });
-
- // Check if getElementsByClassName can be trusted
- support.getElementsByClassName = assert(function( div ) {
- div.innerHTML = "";
-
- // Support: Safari<4
- // Catch class over-caching
- div.firstChild.className = "i";
- // Support: Opera<10
- // Catch gEBCN failure to find non-leading classes
- return div.getElementsByClassName("i").length === 2;
- });
-
- // Support: IE<10
- // Check if getElementById returns elements by name
- // The broken getElementById methods don't pick up programatically-set names,
- // so use a roundabout getElementsByName test
- support.getById = assert(function( div ) {
- docElem.appendChild( div ).id = expando;
- return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
- });
-
- // ID find and filter
- if ( support.getById ) {
- Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
- var m = context.getElementById( id );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- return m && m.parentNode ? [m] : [];
- }
- };
- Expr.filter["ID"] = function( id ) {
- var attrId = id.replace( runescape, funescape );
- return function( elem ) {
- return elem.getAttribute("id") === attrId;
- };
- };
- } else {
- // Support: IE6/7
- // getElementById is not reliable as a find shortcut
- delete Expr.find["ID"];
-
- Expr.filter["ID"] = function( id ) {
- var attrId = id.replace( runescape, funescape );
- return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
- return node && node.value === attrId;
- };
- };
- }
-
- // Tag
- Expr.find["TAG"] = support.getElementsByTagName ?
- function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
- return context.getElementsByTagName( tag );
- }
- } :
- function( tag, context ) {
- var elem,
- tmp = [],
- i = 0,
- results = context.getElementsByTagName( tag );
-
- // Filter out possible comments
- if ( tag === "*" ) {
- while ( (elem = results[i++]) ) {
- if ( elem.nodeType === 1 ) {
- tmp.push( elem );
- }
- }
-
- return tmp;
- }
- return results;
- };
-
- // Class
- Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
- if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
- return context.getElementsByClassName( className );
- }
- };
-
- /* QSA/matchesSelector
- ---------------------------------------------------------------------- */
-
- // QSA and matchesSelector support
-
- // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
- rbuggyMatches = [];
-
- // qSa(:focus) reports false when true (Chrome 21)
- // We allow this because of a bug in IE8/9 that throws an error
- // whenever `document.activeElement` is accessed on an iframe
- // So, we allow :focus to pass through QSA all the time to avoid the IE error
- // See http://bugs.jquery.com/ticket/13378
- rbuggyQSA = [];
-
- if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
- // Build QSA regex
- // Regex strategy adopted from Diego Perini
- assert(function( div ) {
- // Select is set to empty string on purpose
- // This is to test IE's treatment of not explicitly
- // setting a boolean content attribute,
- // since its presence should be enough
- // http://bugs.jquery.com/ticket/12359
- div.innerHTML = "";
-
- // Support: IE8
- // Boolean attributes and "value" are not treated correctly
- if ( !div.querySelectorAll("[selected]").length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
- }
-
- // Webkit/Opera - :checked should return selected option elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- // IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":checked").length ) {
- rbuggyQSA.push(":checked");
- }
- });
-
- assert(function( div ) {
-
- // Support: Opera 10-12/IE8
- // ^= $= *= and empty values
- // Should not select anything
- // Support: Windows 8 Native Apps
- // The type attribute is restricted during .innerHTML assignment
- var input = doc.createElement("input");
- input.setAttribute( "type", "hidden" );
- div.appendChild( input ).setAttribute( "t", "" );
-
- if ( div.querySelectorAll("[t^='']").length ) {
- rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
- }
-
- // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
- // IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":enabled").length ) {
- rbuggyQSA.push( ":enabled", ":disabled" );
- }
-
- // Opera 10-11 does not throw on post-comma invalid pseudos
- div.querySelectorAll("*,:x");
- rbuggyQSA.push(",.*:");
- });
- }
-
- if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
- docElem.mozMatchesSelector ||
- docElem.oMatchesSelector ||
- docElem.msMatchesSelector) )) ) {
-
- assert(function( div ) {
- // Check to see if it's possible to do matchesSelector
- // on a disconnected node (IE 9)
- support.disconnectedMatch = matches.call( div, "div" );
-
- // This should fail with an exception
- // Gecko does not error, returns false instead
- matches.call( div, "[s!='']:x" );
- rbuggyMatches.push( "!=", pseudos );
- });
- }
-
- rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
- rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
-
- /* Contains
- ---------------------------------------------------------------------- */
-
- // Element contains another
- // Purposefully does not implement inclusive descendent
- // As in, an element does not contain itself
- contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
- function( a, b ) {
- var adown = a.nodeType === 9 ? a.documentElement : a,
- bup = b && b.parentNode;
- return a === bup || !!( bup && bup.nodeType === 1 && (
- adown.contains ?
- adown.contains( bup ) :
- a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
- ));
- } :
- function( a, b ) {
- if ( b ) {
- while ( (b = b.parentNode) ) {
- if ( b === a ) {
- return true;
- }
- }
- }
- return false;
- };
-
- /* Sorting
- ---------------------------------------------------------------------- */
-
- // Document order sorting
- sortOrder = docElem.compareDocumentPosition ?
- function( a, b ) {
-
- // Flag for duplicate removal
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
-
- if ( compare ) {
- // Disconnected nodes
- if ( compare & 1 ||
- (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
-
- // Choose the first element that is related to our preferred document
- if ( a === doc || contains(preferredDoc, a) ) {
- return -1;
- }
- if ( b === doc || contains(preferredDoc, b) ) {
- return 1;
- }
-
- // Maintain original order
- return sortInput ?
- ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
- 0;
- }
-
- return compare & 4 ? -1 : 1;
- }
-
- // Not directly comparable, sort on existence of method
- return a.compareDocumentPosition ? -1 : 1;
- } :
- function( a, b ) {
- var cur,
- i = 0,
- aup = a.parentNode,
- bup = b.parentNode,
- ap = [ a ],
- bp = [ b ];
-
- // Exit early if the nodes are identical
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
-
- // Parentless nodes are either documents or disconnected
- } else if ( !aup || !bup ) {
- return a === doc ? -1 :
- b === doc ? 1 :
- aup ? -1 :
- bup ? 1 :
- sortInput ?
- ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
- 0;
-
- // If the nodes are siblings, we can do a quick check
- } else if ( aup === bup ) {
- return siblingCheck( a, b );
- }
-
- // Otherwise we need full lists of their ancestors for comparison
- cur = a;
- while ( (cur = cur.parentNode) ) {
- ap.unshift( cur );
- }
- cur = b;
- while ( (cur = cur.parentNode) ) {
- bp.unshift( cur );
- }
-
- // Walk down the tree looking for a discrepancy
- while ( ap[i] === bp[i] ) {
- i++;
- }
-
- return i ?
- // Do a sibling check if the nodes have a common ancestor
- siblingCheck( ap[i], bp[i] ) :
-
- // Otherwise nodes in our document sort first
- ap[i] === preferredDoc ? -1 :
- bp[i] === preferredDoc ? 1 :
- 0;
- };
-
- return doc;
-};
-
-Sizzle.matches = function( expr, elements ) {
- return Sizzle( expr, null, null, elements );
-};
-
-Sizzle.matchesSelector = function( elem, expr ) {
- // Set document vars if needed
- if ( ( elem.ownerDocument || elem ) !== document ) {
- setDocument( elem );
- }
-
- // Make sure that attribute selectors are quoted
- expr = expr.replace( rattributeQuotes, "='$1']" );
-
- if ( support.matchesSelector && documentIsHTML &&
- ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
- ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
-
- try {
- var ret = matches.call( elem, expr );
-
- // IE 9's matchesSelector returns false on disconnected nodes
- if ( ret || support.disconnectedMatch ||
- // As well, disconnected nodes are said to be in a document
- // fragment in IE 9
- elem.document && elem.document.nodeType !== 11 ) {
- return ret;
- }
- } catch(e) {}
- }
-
- return Sizzle( expr, document, null, [elem] ).length > 0;
-};
-
-Sizzle.contains = function( context, elem ) {
- // Set document vars if needed
- if ( ( context.ownerDocument || context ) !== document ) {
- setDocument( context );
- }
- return contains( context, elem );
-};
-
-Sizzle.attr = function( elem, name ) {
- // Set document vars if needed
- if ( ( elem.ownerDocument || elem ) !== document ) {
- setDocument( elem );
- }
-
- var fn = Expr.attrHandle[ name.toLowerCase() ],
- // Don't get fooled by Object.prototype properties (jQuery #13807)
- val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
- fn( elem, name, !documentIsHTML ) :
- undefined;
-
- return val === undefined ?
- support.attributes || !documentIsHTML ?
- elem.getAttribute( name ) :
- (val = elem.getAttributeNode(name)) && val.specified ?
- val.value :
- null :
- val;
-};
-
-Sizzle.error = function( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
-};
-
-/**
- * Document sorting and removing duplicates
- * @param {ArrayLike} results
- */
-Sizzle.uniqueSort = function( results ) {
- var elem,
- duplicates = [],
- j = 0,
- i = 0;
-
- // Unless we *know* we can detect duplicates, assume their presence
- hasDuplicate = !support.detectDuplicates;
- sortInput = !support.sortStable && results.slice( 0 );
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- while ( (elem = results[i++]) ) {
- if ( elem === results[ i ] ) {
- j = duplicates.push( i );
- }
- }
- while ( j-- ) {
- results.splice( duplicates[ j ], 1 );
- }
- }
-
- return results;
-};
-
-/**
- * Utility function for retrieving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-getText = Sizzle.getText = function( elem ) {
- var node,
- ret = "",
- i = 0,
- nodeType = elem.nodeType;
-
- if ( !nodeType ) {
- // If no nodeType, this is expected to be an array
- for ( ; (node = elem[i]); i++ ) {
- // Do not traverse comment nodes
- ret += getText( node );
- }
- } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
- // Use textContent for elements
- // innerText usage removed for consistency of new lines (see #11153)
- if ( typeof elem.textContent === "string" ) {
- return elem.textContent;
- } else {
- // Traverse its children
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- ret += getText( elem );
- }
- }
- } else if ( nodeType === 3 || nodeType === 4 ) {
- return elem.nodeValue;
- }
- // Do not include comment or processing instruction nodes
-
- return ret;
-};
-
-Expr = Sizzle.selectors = {
-
- // Can be adjusted by the user
- cacheLength: 50,
-
- createPseudo: markFunction,
-
- match: matchExpr,
-
- attrHandle: {},
-
- find: {},
-
- relative: {
- ">": { dir: "parentNode", first: true },
- " ": { dir: "parentNode" },
- "+": { dir: "previousSibling", first: true },
- "~": { dir: "previousSibling" }
- },
-
- preFilter: {
- "ATTR": function( match ) {
- match[1] = match[1].replace( runescape, funescape );
-
- // Move the given value to match[3] whether quoted or unquoted
- match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
-
- if ( match[2] === "~=" ) {
- match[3] = " " + match[3] + " ";
- }
-
- return match.slice( 0, 4 );
- },
-
- "CHILD": function( match ) {
- /* matches from matchExpr["CHILD"]
- 1 type (only|nth|...)
- 2 what (child|of-type)
- 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
- 4 xn-component of xn+y argument ([+-]?\d*n|)
- 5 sign of xn-component
- 6 x of xn-component
- 7 sign of y-component
- 8 y of y-component
- */
- match[1] = match[1].toLowerCase();
-
- if ( match[1].slice( 0, 3 ) === "nth" ) {
- // nth-* requires argument
- if ( !match[3] ) {
- Sizzle.error( match[0] );
- }
-
- // numeric x and y parameters for Expr.filter.CHILD
- // remember that false/true cast respectively to 0/1
- match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
- match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
-
- // other types prohibit arguments
- } else if ( match[3] ) {
- Sizzle.error( match[0] );
- }
-
- return match;
- },
-
- "PSEUDO": function( match ) {
- var excess,
- unquoted = !match[5] && match[2];
-
- if ( matchExpr["CHILD"].test( match[0] ) ) {
- return null;
- }
-
- // Accept quoted arguments as-is
- if ( match[3] && match[4] !== undefined ) {
- match[2] = match[4];
-
- // Strip excess characters from unquoted arguments
- } else if ( unquoted && rpseudo.test( unquoted ) &&
- // Get excess from tokenize (recursively)
- (excess = tokenize( unquoted, true )) &&
- // advance to the next closing parenthesis
- (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
-
- // excess is a negative index
- match[0] = match[0].slice( 0, excess );
- match[2] = unquoted.slice( 0, excess );
- }
-
- // Return only captures needed by the pseudo filter method (type and argument)
- return match.slice( 0, 3 );
- }
- },
-
- filter: {
-
- "TAG": function( nodeNameSelector ) {
- var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
- return nodeNameSelector === "*" ?
- function() { return true; } :
- function( elem ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
- };
- },
-
- "CLASS": function( className ) {
- var pattern = classCache[ className + " " ];
-
- return pattern ||
- (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
- classCache( className, function( elem ) {
- return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
- });
- },
-
- "ATTR": function( name, operator, check ) {
- return function( elem ) {
- var result = Sizzle.attr( elem, name );
-
- if ( result == null ) {
- return operator === "!=";
- }
- if ( !operator ) {
- return true;
- }
-
- result += "";
-
- return operator === "=" ? result === check :
- operator === "!=" ? result !== check :
- operator === "^=" ? check && result.indexOf( check ) === 0 :
- operator === "*=" ? check && result.indexOf( check ) > -1 :
- operator === "$=" ? check && result.slice( -check.length ) === check :
- operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
- operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
- false;
- };
- },
-
- "CHILD": function( type, what, argument, first, last ) {
- var simple = type.slice( 0, 3 ) !== "nth",
- forward = type.slice( -4 ) !== "last",
- ofType = what === "of-type";
-
- return first === 1 && last === 0 ?
-
- // Shortcut for :nth-*(n)
- function( elem ) {
- return !!elem.parentNode;
- } :
-
- function( elem, context, xml ) {
- var cache, outerCache, node, diff, nodeIndex, start,
- dir = simple !== forward ? "nextSibling" : "previousSibling",
- parent = elem.parentNode,
- name = ofType && elem.nodeName.toLowerCase(),
- useCache = !xml && !ofType;
-
- if ( parent ) {
-
- // :(first|last|only)-(child|of-type)
- if ( simple ) {
- while ( dir ) {
- node = elem;
- while ( (node = node[ dir ]) ) {
- if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
- return false;
- }
- }
- // Reverse direction for :only-* (if we haven't yet done so)
- start = dir = type === "only" && !start && "nextSibling";
- }
- return true;
- }
-
- start = [ forward ? parent.firstChild : parent.lastChild ];
-
- // non-xml :nth-child(...) stores cache data on `parent`
- if ( forward && useCache ) {
- // Seek `elem` from a previously-cached index
- outerCache = parent[ expando ] || (parent[ expando ] = {});
- cache = outerCache[ type ] || [];
- nodeIndex = cache[0] === dirruns && cache[1];
- diff = cache[0] === dirruns && cache[2];
- node = nodeIndex && parent.childNodes[ nodeIndex ];
-
- while ( (node = ++nodeIndex && node && node[ dir ] ||
-
- // Fallback to seeking `elem` from the start
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- // When found, cache indexes on `parent` and break
- if ( node.nodeType === 1 && ++diff && node === elem ) {
- outerCache[ type ] = [ dirruns, nodeIndex, diff ];
- break;
- }
- }
-
- // Use previously-cached element index if available
- } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
- diff = cache[1];
-
- // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
- } else {
- // Use the same loop as above to seek `elem` from the start
- while ( (node = ++nodeIndex && node && node[ dir ] ||
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
- // Cache the index of each encountered element
- if ( useCache ) {
- (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
- }
-
- if ( node === elem ) {
- break;
- }
- }
- }
- }
-
- // Incorporate the offset, then check against cycle size
- diff -= last;
- return diff === first || ( diff % first === 0 && diff / first >= 0 );
- }
- };
- },
-
- "PSEUDO": function( pseudo, argument ) {
- // pseudo-class names are case-insensitive
- // http://www.w3.org/TR/selectors/#pseudo-classes
- // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
- // Remember that setFilters inherits from pseudos
- var args,
- fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
- Sizzle.error( "unsupported pseudo: " + pseudo );
-
- // The user may use createPseudo to indicate that
- // arguments are needed to create the filter function
- // just as Sizzle does
- if ( fn[ expando ] ) {
- return fn( argument );
- }
-
- // But maintain support for old signatures
- if ( fn.length > 1 ) {
- args = [ pseudo, pseudo, "", argument ];
- return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
- markFunction(function( seed, matches ) {
- var idx,
- matched = fn( seed, argument ),
- i = matched.length;
- while ( i-- ) {
- idx = indexOf.call( seed, matched[i] );
- seed[ idx ] = !( matches[ idx ] = matched[i] );
- }
- }) :
- function( elem ) {
- return fn( elem, 0, args );
- };
- }
-
- return fn;
- }
- },
-
- pseudos: {
- // Potentially complex pseudos
- "not": markFunction(function( selector ) {
- // Trim the selector passed to compile
- // to avoid treating leading and trailing
- // spaces as combinators
- var input = [],
- results = [],
- matcher = compile( selector.replace( rtrim, "$1" ) );
-
- return matcher[ expando ] ?
- markFunction(function( seed, matches, context, xml ) {
- var elem,
- unmatched = matcher( seed, null, xml, [] ),
- i = seed.length;
-
- // Match elements unmatched by `matcher`
- while ( i-- ) {
- if ( (elem = unmatched[i]) ) {
- seed[i] = !(matches[i] = elem);
- }
- }
- }) :
- function( elem, context, xml ) {
- input[0] = elem;
- matcher( input, null, xml, results );
- return !results.pop();
- };
- }),
-
- "has": markFunction(function( selector ) {
- return function( elem ) {
- return Sizzle( selector, elem ).length > 0;
- };
- }),
-
- "contains": markFunction(function( text ) {
- return function( elem ) {
- return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
- };
- }),
-
- // "Whether an element is represented by a :lang() selector
- // is based solely on the element's language value
- // being equal to the identifier C,
- // or beginning with the identifier C immediately followed by "-".
- // The matching of C against the element's language value is performed case-insensitively.
- // The identifier C does not have to be a valid language name."
- // http://www.w3.org/TR/selectors/#lang-pseudo
- "lang": markFunction( function( lang ) {
- // lang value must be a valid identifier
- if ( !ridentifier.test(lang || "") ) {
- Sizzle.error( "unsupported lang: " + lang );
- }
- lang = lang.replace( runescape, funescape ).toLowerCase();
- return function( elem ) {
- var elemLang;
- do {
- if ( (elemLang = documentIsHTML ?
- elem.lang :
- elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
-
- elemLang = elemLang.toLowerCase();
- return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
- }
- } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
- return false;
- };
- }),
-
- // Miscellaneous
- "target": function( elem ) {
- var hash = window.location && window.location.hash;
- return hash && hash.slice( 1 ) === elem.id;
- },
-
- "root": function( elem ) {
- return elem === docElem;
- },
-
- "focus": function( elem ) {
- return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
- },
-
- // Boolean properties
- "enabled": function( elem ) {
- return elem.disabled === false;
- },
-
- "disabled": function( elem ) {
- return elem.disabled === true;
- },
-
- "checked": function( elem ) {
- // In CSS3, :checked should return both checked and selected elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- var nodeName = elem.nodeName.toLowerCase();
- return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
- },
-
- "selected": function( elem ) {
- // Accessing this property makes selected-by-default
- // options in Safari work properly
- if ( elem.parentNode ) {
- elem.parentNode.selectedIndex;
- }
-
- return elem.selected === true;
- },
-
- // Contents
- "empty": function( elem ) {
- // http://www.w3.org/TR/selectors/#empty-pseudo
- // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
- // not comment, processing instructions, or others
- // Thanks to Diego Perini for the nodeName shortcut
- // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
- return false;
- }
- }
- return true;
- },
-
- "parent": function( elem ) {
- return !Expr.pseudos["empty"]( elem );
- },
-
- // Element/input types
- "header": function( elem ) {
- return rheader.test( elem.nodeName );
- },
-
- "input": function( elem ) {
- return rinputs.test( elem.nodeName );
- },
-
- "button": function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === "button" || name === "button";
- },
-
- "text": function( elem ) {
- var attr;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
- // use getAttribute instead to test this case
- return elem.nodeName.toLowerCase() === "input" &&
- elem.type === "text" &&
- ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
- },
-
- // Position-in-collection
- "first": createPositionalPseudo(function() {
- return [ 0 ];
- }),
-
- "last": createPositionalPseudo(function( matchIndexes, length ) {
- return [ length - 1 ];
- }),
-
- "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
- return [ argument < 0 ? argument + length : argument ];
- }),
-
- "even": createPositionalPseudo(function( matchIndexes, length ) {
- var i = 0;
- for ( ; i < length; i += 2 ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "odd": createPositionalPseudo(function( matchIndexes, length ) {
- var i = 1;
- for ( ; i < length; i += 2 ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
- var i = argument < 0 ? argument + length : argument;
- for ( ; --i >= 0; ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
- var i = argument < 0 ? argument + length : argument;
- for ( ; ++i < length; ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- })
- }
-};
-
-Expr.pseudos["nth"] = Expr.pseudos["eq"];
-
-// Add button/input type pseudos
-for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
- Expr.pseudos[ i ] = createInputPseudo( i );
-}
-for ( i in { submit: true, reset: true } ) {
- Expr.pseudos[ i ] = createButtonPseudo( i );
-}
-
-// Easy API for creating new setFilters
-function setFilters() {}
-setFilters.prototype = Expr.filters = Expr.pseudos;
-Expr.setFilters = new setFilters();
-
-function tokenize( selector, parseOnly ) {
- var matched, match, tokens, type,
- soFar, groups, preFilters,
- cached = tokenCache[ selector + " " ];
-
- if ( cached ) {
- return parseOnly ? 0 : cached.slice( 0 );
- }
-
- soFar = selector;
- groups = [];
- preFilters = Expr.preFilter;
-
- while ( soFar ) {
-
- // Comma and first run
- if ( !matched || (match = rcomma.exec( soFar )) ) {
- if ( match ) {
- // Don't consume trailing commas as valid
- soFar = soFar.slice( match[0].length ) || soFar;
- }
- groups.push( tokens = [] );
- }
-
- matched = false;
-
- // Combinators
- if ( (match = rcombinators.exec( soFar )) ) {
- matched = match.shift();
- tokens.push({
- value: matched,
- // Cast descendant combinators to space
- type: match[0].replace( rtrim, " " )
- });
- soFar = soFar.slice( matched.length );
- }
-
- // Filters
- for ( type in Expr.filter ) {
- if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
- (match = preFilters[ type ]( match ))) ) {
- matched = match.shift();
- tokens.push({
- value: matched,
- type: type,
- matches: match
- });
- soFar = soFar.slice( matched.length );
- }
- }
-
- if ( !matched ) {
- break;
- }
- }
-
- // Return the length of the invalid excess
- // if we're just parsing
- // Otherwise, throw an error or return tokens
- return parseOnly ?
- soFar.length :
- soFar ?
- Sizzle.error( selector ) :
- // Cache the tokens
- tokenCache( selector, groups ).slice( 0 );
-}
-
-function toSelector( tokens ) {
- var i = 0,
- len = tokens.length,
- selector = "";
- for ( ; i < len; i++ ) {
- selector += tokens[i].value;
- }
- return selector;
-}
-
-function addCombinator( matcher, combinator, base ) {
- var dir = combinator.dir,
- checkNonElements = base && dir === "parentNode",
- doneName = done++;
-
- return combinator.first ?
- // Check against closest ancestor/preceding element
- function( elem, context, xml ) {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- return matcher( elem, context, xml );
- }
- }
- } :
-
- // Check against all ancestor/preceding elements
- function( elem, context, xml ) {
- var data, cache, outerCache,
- dirkey = dirruns + " " + doneName;
-
- // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
- if ( xml ) {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- if ( matcher( elem, context, xml ) ) {
- return true;
- }
- }
- }
- } else {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- outerCache = elem[ expando ] || (elem[ expando ] = {});
- if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
- if ( (data = cache[1]) === true || data === cachedruns ) {
- return data === true;
- }
- } else {
- cache = outerCache[ dir ] = [ dirkey ];
- cache[1] = matcher( elem, context, xml ) || cachedruns;
- if ( cache[1] === true ) {
- return true;
- }
- }
- }
- }
- }
- };
-}
-
-function elementMatcher( matchers ) {
- return matchers.length > 1 ?
- function( elem, context, xml ) {
- var i = matchers.length;
- while ( i-- ) {
- if ( !matchers[i]( elem, context, xml ) ) {
- return false;
- }
- }
- return true;
- } :
- matchers[0];
-}
-
-function condense( unmatched, map, filter, context, xml ) {
- var elem,
- newUnmatched = [],
- i = 0,
- len = unmatched.length,
- mapped = map != null;
-
- for ( ; i < len; i++ ) {
- if ( (elem = unmatched[i]) ) {
- if ( !filter || filter( elem, context, xml ) ) {
- newUnmatched.push( elem );
- if ( mapped ) {
- map.push( i );
- }
- }
- }
- }
-
- return newUnmatched;
-}
-
-function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
- if ( postFilter && !postFilter[ expando ] ) {
- postFilter = setMatcher( postFilter );
- }
- if ( postFinder && !postFinder[ expando ] ) {
- postFinder = setMatcher( postFinder, postSelector );
- }
- return markFunction(function( seed, results, context, xml ) {
- var temp, i, elem,
- preMap = [],
- postMap = [],
- preexisting = results.length,
-
- // Get initial elements from seed or context
- elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
-
- // Prefilter to get matcher input, preserving a map for seed-results synchronization
- matcherIn = preFilter && ( seed || !selector ) ?
- condense( elems, preMap, preFilter, context, xml ) :
- elems,
-
- matcherOut = matcher ?
- // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
- postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
-
- // ...intermediate processing is necessary
- [] :
-
- // ...otherwise use results directly
- results :
- matcherIn;
-
- // Find primary matches
- if ( matcher ) {
- matcher( matcherIn, matcherOut, context, xml );
- }
-
- // Apply postFilter
- if ( postFilter ) {
- temp = condense( matcherOut, postMap );
- postFilter( temp, [], context, xml );
-
- // Un-match failing elements by moving them back to matcherIn
- i = temp.length;
- while ( i-- ) {
- if ( (elem = temp[i]) ) {
- matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
- }
- }
- }
-
- if ( seed ) {
- if ( postFinder || preFilter ) {
- if ( postFinder ) {
- // Get the final matcherOut by condensing this intermediate into postFinder contexts
- temp = [];
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) ) {
- // Restore matcherIn since elem is not yet a final match
- temp.push( (matcherIn[i] = elem) );
- }
- }
- postFinder( null, (matcherOut = []), temp, xml );
- }
-
- // Move matched elements from seed to results to keep them synchronized
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) &&
- (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
-
- seed[temp] = !(results[temp] = elem);
- }
- }
- }
-
- // Add elements to results, through postFinder if defined
- } else {
- matcherOut = condense(
- matcherOut === results ?
- matcherOut.splice( preexisting, matcherOut.length ) :
- matcherOut
- );
- if ( postFinder ) {
- postFinder( null, results, matcherOut, xml );
- } else {
- push.apply( results, matcherOut );
- }
- }
- });
-}
-
-function matcherFromTokens( tokens ) {
- var checkContext, matcher, j,
- len = tokens.length,
- leadingRelative = Expr.relative[ tokens[0].type ],
- implicitRelative = leadingRelative || Expr.relative[" "],
- i = leadingRelative ? 1 : 0,
-
- // The foundational matcher ensures that elements are reachable from top-level context(s)
- matchContext = addCombinator( function( elem ) {
- return elem === checkContext;
- }, implicitRelative, true ),
- matchAnyContext = addCombinator( function( elem ) {
- return indexOf.call( checkContext, elem ) > -1;
- }, implicitRelative, true ),
- matchers = [ function( elem, context, xml ) {
- return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
- (checkContext = context).nodeType ?
- matchContext( elem, context, xml ) :
- matchAnyContext( elem, context, xml ) );
- } ];
-
- for ( ; i < len; i++ ) {
- if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
- matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
- } else {
- matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
-
- // Return special upon seeing a positional matcher
- if ( matcher[ expando ] ) {
- // Find the next relative operator (if any) for proper handling
- j = ++i;
- for ( ; j < len; j++ ) {
- if ( Expr.relative[ tokens[j].type ] ) {
- break;
- }
- }
- return setMatcher(
- i > 1 && elementMatcher( matchers ),
- i > 1 && toSelector(
- // If the preceding token was a descendant combinator, insert an implicit any-element `*`
- tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
- ).replace( rtrim, "$1" ),
- matcher,
- i < j && matcherFromTokens( tokens.slice( i, j ) ),
- j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
- j < len && toSelector( tokens )
- );
- }
- matchers.push( matcher );
- }
- }
-
- return elementMatcher( matchers );
-}
-
-function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
- // A counter to specify which element is currently being matched
- var matcherCachedRuns = 0,
- bySet = setMatchers.length > 0,
- byElement = elementMatchers.length > 0,
- superMatcher = function( seed, context, xml, results, expandContext ) {
- var elem, j, matcher,
- setMatched = [],
- matchedCount = 0,
- i = "0",
- unmatched = seed && [],
- outermost = expandContext != null,
- contextBackup = outermostContext,
- // We must always have either seed elements or context
- elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
- // Use integer dirruns iff this is the outermost matcher
- dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
-
- if ( outermost ) {
- outermostContext = context !== document && context;
- cachedruns = matcherCachedRuns;
- }
-
- // Add elements passing elementMatchers directly to results
- // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
- for ( ; (elem = elems[i]) != null; i++ ) {
- if ( byElement && elem ) {
- j = 0;
- while ( (matcher = elementMatchers[j++]) ) {
- if ( matcher( elem, context, xml ) ) {
- results.push( elem );
- break;
- }
- }
- if ( outermost ) {
- dirruns = dirrunsUnique;
- cachedruns = ++matcherCachedRuns;
- }
- }
-
- // Track unmatched elements for set filters
- if ( bySet ) {
- // They will have gone through all possible matchers
- if ( (elem = !matcher && elem) ) {
- matchedCount--;
- }
-
- // Lengthen the array for every element, matched or not
- if ( seed ) {
- unmatched.push( elem );
- }
- }
- }
-
- // Apply set filters to unmatched elements
- matchedCount += i;
- if ( bySet && i !== matchedCount ) {
- j = 0;
- while ( (matcher = setMatchers[j++]) ) {
- matcher( unmatched, setMatched, context, xml );
- }
-
- if ( seed ) {
- // Reintegrate element matches to eliminate the need for sorting
- if ( matchedCount > 0 ) {
- while ( i-- ) {
- if ( !(unmatched[i] || setMatched[i]) ) {
- setMatched[i] = pop.call( results );
- }
- }
- }
-
- // Discard index placeholder values to get only actual matches
- setMatched = condense( setMatched );
- }
-
- // Add matches to results
- push.apply( results, setMatched );
-
- // Seedless set matches succeeding multiple successful matchers stipulate sorting
- if ( outermost && !seed && setMatched.length > 0 &&
- ( matchedCount + setMatchers.length ) > 1 ) {
-
- Sizzle.uniqueSort( results );
- }
- }
-
- // Override manipulation of globals by nested matchers
- if ( outermost ) {
- dirruns = dirrunsUnique;
- outermostContext = contextBackup;
- }
-
- return unmatched;
- };
-
- return bySet ?
- markFunction( superMatcher ) :
- superMatcher;
-}
-
-compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
- var i,
- setMatchers = [],
- elementMatchers = [],
- cached = compilerCache[ selector + " " ];
-
- if ( !cached ) {
- // Generate a function of recursive functions that can be used to check each element
- if ( !group ) {
- group = tokenize( selector );
- }
- i = group.length;
- while ( i-- ) {
- cached = matcherFromTokens( group[i] );
- if ( cached[ expando ] ) {
- setMatchers.push( cached );
- } else {
- elementMatchers.push( cached );
- }
- }
-
- // Cache the compiled function
- cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
- }
- return cached;
-};
-
-function multipleContexts( selector, contexts, results ) {
- var i = 0,
- len = contexts.length;
- for ( ; i < len; i++ ) {
- Sizzle( selector, contexts[i], results );
- }
- return results;
-}
-
-function select( selector, context, results, seed ) {
- var i, tokens, token, type, find,
- match = tokenize( selector );
-
- if ( !seed ) {
- // Try to minimize operations if there is only one group
- if ( match.length === 1 ) {
-
- // Take a shortcut and set the context if the root selector is an ID
- tokens = match[0] = match[0].slice( 0 );
- if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
- support.getById && context.nodeType === 9 && documentIsHTML &&
- Expr.relative[ tokens[1].type ] ) {
-
- context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
- if ( !context ) {
- return results;
- }
- selector = selector.slice( tokens.shift().value.length );
- }
-
- // Fetch a seed set for right-to-left matching
- i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
- while ( i-- ) {
- token = tokens[i];
-
- // Abort if we hit a combinator
- if ( Expr.relative[ (type = token.type) ] ) {
- break;
- }
- if ( (find = Expr.find[ type ]) ) {
- // Search, expanding context for leading sibling combinators
- if ( (seed = find(
- token.matches[0].replace( runescape, funescape ),
- rsibling.test( tokens[0].type ) && context.parentNode || context
- )) ) {
-
- // If seed is empty or no tokens remain, we can return early
- tokens.splice( i, 1 );
- selector = seed.length && toSelector( tokens );
- if ( !selector ) {
- push.apply( results, seed );
- return results;
- }
-
- break;
- }
- }
- }
- }
- }
-
- // Compile and execute a filtering function
- // Provide `match` to avoid retokenization if we modified the selector above
- compile( selector, match )(
- seed,
- context,
- !documentIsHTML,
- results,
- rsibling.test( selector )
- );
- return results;
-}
-
-// One-time assignments
-
-// Sort stability
-support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
-
-// Support: Chrome<14
-// Always assume duplicates if they aren't passed to the comparison function
-support.detectDuplicates = hasDuplicate;
-
-// Initialize against the default document
-setDocument();
-
-// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
-// Detached nodes confoundingly follow *each other*
-support.sortDetached = assert(function( div1 ) {
- // Should return 1, but returns 4 (following)
- return div1.compareDocumentPosition( document.createElement("div") ) & 1;
-});
-
-// Support: IE<8
-// Prevent attribute/property "interpolation"
-// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
-if ( !assert(function( div ) {
- div.innerHTML = "";
- return div.firstChild.getAttribute("href") === "#" ;
-}) ) {
- addHandle( "type|href|height|width", function( elem, name, isXML ) {
- if ( !isXML ) {
- return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
- }
- });
-}
-
-// Support: IE<9
-// Use defaultValue in place of getAttribute("value")
-if ( !support.attributes || !assert(function( div ) {
- div.innerHTML = "";
- div.firstChild.setAttribute( "value", "" );
- return div.firstChild.getAttribute( "value" ) === "";
-}) ) {
- addHandle( "value", function( elem, name, isXML ) {
- if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
- return elem.defaultValue;
- }
- });
-}
-
-// Support: IE<9
-// Use getAttributeNode to fetch booleans when getAttribute lies
-if ( !assert(function( div ) {
- return div.getAttribute("disabled") == null;
-}) ) {
- addHandle( booleans, function( elem, name, isXML ) {
- var val;
- if ( !isXML ) {
- return (val = elem.getAttributeNode( name )) && val.specified ?
- val.value :
- elem[ name ] === true ? name.toLowerCase() : null;
- }
- });
-}
-
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.pseudos;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-})( window );
-// String to Object options format cache
-var optionsCache = {};
-
-// Convert String-formatted options into Object-formatted ones and store in cache
-function createOptions( options ) {
- var object = optionsCache[ options ] = {};
- jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
- object[ flag ] = true;
- });
- return object;
-}
-
-/*
- * Create a callback list using the following parameters:
- *
- * options: an optional list of space-separated options that will change how
- * the callback list behaves or a more traditional option object
- *
- * By default a callback list will act like an event callback list and can be
- * "fired" multiple times.
- *
- * Possible options:
- *
- * once: will ensure the callback list can only be fired once (like a Deferred)
- *
- * memory: will keep track of previous values and will call any callback added
- * after the list has been fired right away with the latest "memorized"
- * values (like a Deferred)
- *
- * unique: will ensure a callback can only be added once (no duplicate in the list)
- *
- * stopOnFalse: interrupt callings when a callback returns false
- *
- */
-jQuery.Callbacks = function( options ) {
-
- // Convert options from String-formatted to Object-formatted if needed
- // (we check in cache first)
- options = typeof options === "string" ?
- ( optionsCache[ options ] || createOptions( options ) ) :
- jQuery.extend( {}, options );
-
- var // Flag to know if list is currently firing
- firing,
- // Last fire value (for non-forgettable lists)
- memory,
- // Flag to know if list was already fired
- fired,
- // End of the loop when firing
- firingLength,
- // Index of currently firing callback (modified by remove if needed)
- firingIndex,
- // First callback to fire (used internally by add and fireWith)
- firingStart,
- // Actual callback list
- list = [],
- // Stack of fire calls for repeatable lists
- stack = !options.once && [],
- // Fire callbacks
- fire = function( data ) {
- memory = options.memory && data;
- fired = true;
- firingIndex = firingStart || 0;
- firingStart = 0;
- firingLength = list.length;
- firing = true;
- for ( ; list && firingIndex < firingLength; firingIndex++ ) {
- if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
- memory = false; // To prevent further calls using add
- break;
- }
- }
- firing = false;
- if ( list ) {
- if ( stack ) {
- if ( stack.length ) {
- fire( stack.shift() );
- }
- } else if ( memory ) {
- list = [];
- } else {
- self.disable();
- }
- }
- },
- // Actual Callbacks object
- self = {
- // Add a callback or a collection of callbacks to the list
- add: function() {
- if ( list ) {
- // First, we save the current length
- var start = list.length;
- (function add( args ) {
- jQuery.each( args, function( _, arg ) {
- var type = jQuery.type( arg );
- if ( type === "function" ) {
- if ( !options.unique || !self.has( arg ) ) {
- list.push( arg );
- }
- } else if ( arg && arg.length && type !== "string" ) {
- // Inspect recursively
- add( arg );
- }
- });
- })( arguments );
- // Do we need to add the callbacks to the
- // current firing batch?
- if ( firing ) {
- firingLength = list.length;
- // With memory, if we're not firing then
- // we should call right away
- } else if ( memory ) {
- firingStart = start;
- fire( memory );
- }
- }
- return this;
- },
- // Remove a callback from the list
- remove: function() {
- if ( list ) {
- jQuery.each( arguments, function( _, arg ) {
- var index;
- while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
- list.splice( index, 1 );
- // Handle firing indexes
- if ( firing ) {
- if ( index <= firingLength ) {
- firingLength--;
- }
- if ( index <= firingIndex ) {
- firingIndex--;
- }
- }
- }
- });
- }
- return this;
- },
- // Check if a given callback is in the list.
- // If no argument is given, return whether or not list has callbacks attached.
- has: function( fn ) {
- return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
- },
- // Remove all callbacks from the list
- empty: function() {
- list = [];
- firingLength = 0;
- return this;
- },
- // Have the list do nothing anymore
- disable: function() {
- list = stack = memory = undefined;
- return this;
- },
- // Is it disabled?
- disabled: function() {
- return !list;
- },
- // Lock the list in its current state
- lock: function() {
- stack = undefined;
- if ( !memory ) {
- self.disable();
- }
- return this;
- },
- // Is it locked?
- locked: function() {
- return !stack;
- },
- // Call all callbacks with the given context and arguments
- fireWith: function( context, args ) {
- if ( list && ( !fired || stack ) ) {
- args = args || [];
- args = [ context, args.slice ? args.slice() : args ];
- if ( firing ) {
- stack.push( args );
- } else {
- fire( args );
- }
- }
- return this;
- },
- // Call all the callbacks with the given arguments
- fire: function() {
- self.fireWith( this, arguments );
- return this;
- },
- // To know if the callbacks have already been called at least once
- fired: function() {
- return !!fired;
- }
- };
-
- return self;
-};
-jQuery.extend({
-
- Deferred: function( func ) {
- var tuples = [
- // action, add listener, listener list, final state
- [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
- [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
- [ "notify", "progress", jQuery.Callbacks("memory") ]
- ],
- state = "pending",
- promise = {
- state: function() {
- return state;
- },
- always: function() {
- deferred.done( arguments ).fail( arguments );
- return this;
- },
- then: function( /* fnDone, fnFail, fnProgress */ ) {
- var fns = arguments;
- return jQuery.Deferred(function( newDefer ) {
- jQuery.each( tuples, function( i, tuple ) {
- var action = tuple[ 0 ],
- fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
- // deferred[ done | fail | progress ] for forwarding actions to newDefer
- deferred[ tuple[1] ](function() {
- var returned = fn && fn.apply( this, arguments );
- if ( returned && jQuery.isFunction( returned.promise ) ) {
- returned.promise()
- .done( newDefer.resolve )
- .fail( newDefer.reject )
- .progress( newDefer.notify );
- } else {
- newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
- }
- });
- });
- fns = null;
- }).promise();
- },
- // Get a promise for this deferred
- // If obj is provided, the promise aspect is added to the object
- promise: function( obj ) {
- return obj != null ? jQuery.extend( obj, promise ) : promise;
- }
- },
- deferred = {};
-
- // Keep pipe for back-compat
- promise.pipe = promise.then;
-
- // Add list-specific methods
- jQuery.each( tuples, function( i, tuple ) {
- var list = tuple[ 2 ],
- stateString = tuple[ 3 ];
-
- // promise[ done | fail | progress ] = list.add
- promise[ tuple[1] ] = list.add;
-
- // Handle state
- if ( stateString ) {
- list.add(function() {
- // state = [ resolved | rejected ]
- state = stateString;
-
- // [ reject_list | resolve_list ].disable; progress_list.lock
- }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
- }
-
- // deferred[ resolve | reject | notify ]
- deferred[ tuple[0] ] = function() {
- deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
- return this;
- };
- deferred[ tuple[0] + "With" ] = list.fireWith;
- });
-
- // Make the deferred a promise
- promise.promise( deferred );
-
- // Call given func if any
- if ( func ) {
- func.call( deferred, deferred );
- }
-
- // All done!
- return deferred;
- },
-
- // Deferred helper
- when: function( subordinate /* , ..., subordinateN */ ) {
- var i = 0,
- resolveValues = core_slice.call( arguments ),
- length = resolveValues.length,
-
- // the count of uncompleted subordinates
- remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
-
- // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
- deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
-
- // Update function for both resolve and progress values
- updateFunc = function( i, contexts, values ) {
- return function( value ) {
- contexts[ i ] = this;
- values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
- if( values === progressValues ) {
- deferred.notifyWith( contexts, values );
- } else if ( !( --remaining ) ) {
- deferred.resolveWith( contexts, values );
- }
- };
- },
-
- progressValues, progressContexts, resolveContexts;
-
- // add listeners to Deferred subordinates; treat others as resolved
- if ( length > 1 ) {
- progressValues = new Array( length );
- progressContexts = new Array( length );
- resolveContexts = new Array( length );
- for ( ; i < length; i++ ) {
- if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
- resolveValues[ i ].promise()
- .done( updateFunc( i, resolveContexts, resolveValues ) )
- .fail( deferred.reject )
- .progress( updateFunc( i, progressContexts, progressValues ) );
- } else {
- --remaining;
- }
- }
- }
-
- // if we're not waiting on anything, resolve the master
- if ( !remaining ) {
- deferred.resolveWith( resolveContexts, resolveValues );
- }
-
- return deferred.promise();
- }
-});
-jQuery.support = (function( support ) {
-
- var all, a, input, select, fragment, opt, eventName, isSupported, i,
- div = document.createElement("div");
-
- // Setup
- div.setAttribute( "className", "t" );
- div.innerHTML = "
a";
-
- // Finish early in limited (non-browser) environments
- all = div.getElementsByTagName("*") || [];
- a = div.getElementsByTagName("a")[ 0 ];
- if ( !a || !a.style || !all.length ) {
- return support;
- }
-
- // First batch of tests
- select = document.createElement("select");
- opt = select.appendChild( document.createElement("option") );
- input = div.getElementsByTagName("input")[ 0 ];
-
- a.style.cssText = "top:1px;float:left;opacity:.5";
-
- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
- support.getSetAttribute = div.className !== "t";
-
- // IE strips leading whitespace when .innerHTML is used
- support.leadingWhitespace = div.firstChild.nodeType === 3;
-
- // Make sure that tbody elements aren't automatically inserted
- // IE will insert them into empty tables
- support.tbody = !div.getElementsByTagName("tbody").length;
-
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- support.htmlSerialize = !!div.getElementsByTagName("link").length;
-
- // Get the style information from getAttribute
- // (IE uses .cssText instead)
- support.style = /top/.test( a.getAttribute("style") );
-
- // Make sure that URLs aren't manipulated
- // (IE normalizes it by default)
- support.hrefNormalized = a.getAttribute("href") === "/a";
-
- // Make sure that element opacity exists
- // (IE uses filter instead)
- // Use a regex to work around a WebKit issue. See #5145
- support.opacity = /^0.5/.test( a.style.opacity );
-
- // Verify style float existence
- // (IE uses styleFloat instead of cssFloat)
- support.cssFloat = !!a.style.cssFloat;
-
- // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
- support.checkOn = !!input.value;
-
- // Make sure that a selected-by-default option has a working selected property.
- // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
- support.optSelected = opt.selected;
-
- // Tests for enctype support on a form (#6743)
- support.enctype = !!document.createElement("form").enctype;
-
- // Makes sure cloning an html5 element does not cause problems
- // Where outerHTML is undefined, this still works
- support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>";
-
- // Will be defined later
- support.inlineBlockNeedsLayout = false;
- support.shrinkWrapBlocks = false;
- support.pixelPosition = false;
- support.deleteExpando = true;
- support.noCloneEvent = true;
- support.reliableMarginRight = true;
- support.boxSizingReliable = true;
-
- // Make sure checked status is properly cloned
- input.checked = true;
- support.noCloneChecked = input.cloneNode( true ).checked;
-
- // Make sure that the options inside disabled selects aren't marked as disabled
- // (WebKit marks them as disabled)
- select.disabled = true;
- support.optDisabled = !opt.disabled;
-
- // Support: IE<9
- try {
- delete div.test;
- } catch( e ) {
- support.deleteExpando = false;
- }
-
- // Check if we can trust getAttribute("value")
- input = document.createElement("input");
- input.setAttribute( "value", "" );
- support.input = input.getAttribute( "value" ) === "";
-
- // Check if an input maintains its value after becoming a radio
- input.value = "t";
- input.setAttribute( "type", "radio" );
- support.radioValue = input.value === "t";
-
- // #11217 - WebKit loses check when the name is after the checked attribute
- input.setAttribute( "checked", "t" );
- input.setAttribute( "name", "t" );
-
- fragment = document.createDocumentFragment();
- fragment.appendChild( input );
-
- // Check if a disconnected checkbox will retain its checked
- // value of true after appended to the DOM (IE6/7)
- support.appendChecked = input.checked;
-
- // WebKit doesn't clone checked state correctly in fragments
- support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
- // Support: IE<9
- // Opera does not clone events (and typeof div.attachEvent === undefined).
- // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
- if ( div.attachEvent ) {
- div.attachEvent( "onclick", function() {
- support.noCloneEvent = false;
- });
-
- div.cloneNode( true ).click();
- }
-
- // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
- // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
- for ( i in { submit: true, change: true, focusin: true }) {
- div.setAttribute( eventName = "on" + i, "t" );
-
- support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
- }
-
- div.style.backgroundClip = "content-box";
- div.cloneNode( true ).style.backgroundClip = "";
- support.clearCloneStyle = div.style.backgroundClip === "content-box";
-
- // Support: IE<9
- // Iteration over object's inherited properties before its own.
- for ( i in jQuery( support ) ) {
- break;
- }
- support.ownLast = i !== "0";
-
- // Run tests that need a body at doc ready
- jQuery(function() {
- var container, marginDiv, tds,
- divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
- body = document.getElementsByTagName("body")[0];
-
- if ( !body ) {
- // Return for frameset docs that don't have a body
- return;
- }
-
- container = document.createElement("div");
- container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
-
- body.appendChild( container ).appendChild( div );
-
- // Support: IE8
- // Check if table cells still have offsetWidth/Height when they are set
- // to display:none and there are still other visible table cells in a
- // table row; if so, offsetWidth/Height are not reliable for use when
- // determining if an element has been hidden directly using
- // display:none (it is still safe to use offsets if a parent element is
- // hidden; don safety goggles and see bug #4512 for more information).
- div.innerHTML = "
t
";
- tds = div.getElementsByTagName("td");
- tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
- isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
- tds[ 0 ].style.display = "";
- tds[ 1 ].style.display = "none";
-
- // Support: IE8
- // Check if empty table cells still have offsetWidth/Height
- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
- // Check box-sizing and margin behavior.
- div.innerHTML = "";
- div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
-
- // Workaround failing boxSizing test due to offsetWidth returning wrong value
- // with some non-1 values of body zoom, ticket #13543
- jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
- support.boxSizing = div.offsetWidth === 4;
- });
-
- // Use window.getComputedStyle because jsdom on node.js will break without it.
- if ( window.getComputedStyle ) {
- support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
- support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
-
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. (#3333)
- // Fails in WebKit before Feb 2011 nightlies
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- marginDiv = div.appendChild( document.createElement("div") );
- marginDiv.style.cssText = div.style.cssText = divReset;
- marginDiv.style.marginRight = marginDiv.style.width = "0";
- div.style.width = "1px";
-
- support.reliableMarginRight =
- !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
- }
-
- if ( typeof div.style.zoom !== core_strundefined ) {
- // Support: IE<8
- // Check if natively block-level elements act like inline-block
- // elements when setting their display to 'inline' and giving
- // them layout
- div.innerHTML = "";
- div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
-
- // Support: IE6
- // Check if elements with layout shrink-wrap their children
- div.style.display = "block";
- div.innerHTML = "";
- div.firstChild.style.width = "5px";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
-
- if ( support.inlineBlockNeedsLayout ) {
- // Prevent IE 6 from affecting layout for positioned elements #11048
- // Prevent IE from shrinking the body in IE 7 mode #12869
- // Support: IE<8
- body.style.zoom = 1;
- }
- }
-
- body.removeChild( container );
-
- // Null elements to avoid leaks in IE
- container = div = tds = marginDiv = null;
- });
-
- // Null elements to avoid leaks in IE
- all = select = fragment = opt = a = input = null;
-
- return support;
-})({});
-
-var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
- rmultiDash = /([A-Z])/g;
-
-function internalData( elem, name, data, pvt /* Internal Use Only */ ){
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var ret, thisCache,
- internalKey = jQuery.expando,
-
- // We have to handle DOM nodes and JS objects differently because IE6-7
- // can't GC object references properly across the DOM-JS boundary
- isNode = elem.nodeType,
-
- // Only DOM nodes need the global jQuery cache; JS object data is
- // attached directly to the object so GC can occur automatically
- cache = isNode ? jQuery.cache : elem,
-
- // Only defining an ID for JS objects if its cache already exists allows
- // the code to shortcut on the same path as a DOM node with no cache
- id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
-
- // Avoid doing any more work than we need to when trying to get data on an
- // object that has no data at all
- if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
- return;
- }
-
- if ( !id ) {
- // Only DOM nodes need a new unique ID for each element since their data
- // ends up in the global cache
- if ( isNode ) {
- id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++;
- } else {
- id = internalKey;
- }
- }
-
- if ( !cache[ id ] ) {
- // Avoid exposing jQuery metadata on plain JS objects when the object
- // is serialized using JSON.stringify
- cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
- }
-
- // An object can be passed to jQuery.data instead of a key/value pair; this gets
- // shallow copied over onto the existing cache
- if ( typeof name === "object" || typeof name === "function" ) {
- if ( pvt ) {
- cache[ id ] = jQuery.extend( cache[ id ], name );
- } else {
- cache[ id ].data = jQuery.extend( cache[ id ].data, name );
- }
- }
-
- thisCache = cache[ id ];
-
- // jQuery data() is stored in a separate object inside the object's internal data
- // cache in order to avoid key collisions between internal data and user-defined
- // data.
- if ( !pvt ) {
- if ( !thisCache.data ) {
- thisCache.data = {};
- }
-
- thisCache = thisCache.data;
- }
-
- if ( data !== undefined ) {
- thisCache[ jQuery.camelCase( name ) ] = data;
- }
-
- // Check for both converted-to-camel and non-converted data property names
- // If a data property was specified
- if ( typeof name === "string" ) {
-
- // First Try to find as-is property data
- ret = thisCache[ name ];
-
- // Test for null|undefined property data
- if ( ret == null ) {
-
- // Try to find the camelCased property
- ret = thisCache[ jQuery.camelCase( name ) ];
- }
- } else {
- ret = thisCache;
- }
-
- return ret;
-}
-
-function internalRemoveData( elem, name, pvt ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, i,
- isNode = elem.nodeType,
-
- // See jQuery.data for more information
- cache = isNode ? jQuery.cache : elem,
- id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
-
- // If there is already no cache entry for this object, there is no
- // purpose in continuing
- if ( !cache[ id ] ) {
- return;
- }
-
- if ( name ) {
-
- thisCache = pvt ? cache[ id ] : cache[ id ].data;
-
- if ( thisCache ) {
-
- // Support array or space separated string names for data keys
- if ( !jQuery.isArray( name ) ) {
-
- // try the string as a key before any manipulation
- if ( name in thisCache ) {
- name = [ name ];
- } else {
-
- // split the camel cased version by spaces unless a key with the spaces exists
- name = jQuery.camelCase( name );
- if ( name in thisCache ) {
- name = [ name ];
- } else {
- name = name.split(" ");
- }
- }
- } else {
- // If "name" is an array of keys...
- // When data is initially created, via ("key", "val") signature,
- // keys will be converted to camelCase.
- // Since there is no way to tell _how_ a key was added, remove
- // both plain key and camelCase key. #12786
- // This will only penalize the array argument path.
- name = name.concat( jQuery.map( name, jQuery.camelCase ) );
- }
-
- i = name.length;
- while ( i-- ) {
- delete thisCache[ name[i] ];
- }
-
- // If there is no data left in the cache, we want to continue
- // and let the cache object itself get destroyed
- if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
- return;
- }
- }
- }
-
- // See jQuery.data for more information
- if ( !pvt ) {
- delete cache[ id ].data;
-
- // Don't destroy the parent cache unless the internal data object
- // had been the only thing left in it
- if ( !isEmptyDataObject( cache[ id ] ) ) {
- return;
- }
- }
-
- // Destroy the cache
- if ( isNode ) {
- jQuery.cleanData( [ elem ], true );
-
- // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
- /* jshint eqeqeq: false */
- } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
- /* jshint eqeqeq: true */
- delete cache[ id ];
-
- // When all else fails, null
- } else {
- cache[ id ] = null;
- }
-}
-
-jQuery.extend({
- cache: {},
-
- // The following elements throw uncatchable exceptions if you
- // attempt to add expando properties to them.
- noData: {
- "applet": true,
- "embed": true,
- // Ban all objects except for Flash (which handle expandos)
- "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
- },
-
- hasData: function( elem ) {
- elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
- return !!elem && !isEmptyDataObject( elem );
- },
-
- data: function( elem, name, data ) {
- return internalData( elem, name, data );
- },
-
- removeData: function( elem, name ) {
- return internalRemoveData( elem, name );
- },
-
- // For internal use only.
- _data: function( elem, name, data ) {
- return internalData( elem, name, data, true );
- },
-
- _removeData: function( elem, name ) {
- return internalRemoveData( elem, name, true );
- },
-
- // A method for determining if a DOM node can handle the data expando
- acceptData: function( elem ) {
- // Do not set data on non-element because it will not be cleared (#8335).
- if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
- return false;
- }
-
- var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
-
- // nodes accept data unless otherwise specified; rejection can be conditional
- return !noData || noData !== true && elem.getAttribute("classid") === noData;
- }
-});
-
-jQuery.fn.extend({
- data: function( key, value ) {
- var attrs, name,
- data = null,
- i = 0,
- elem = this[0];
-
- // Special expections of .data basically thwart jQuery.access,
- // so implement the relevant behavior ourselves
-
- // Gets all values
- if ( key === undefined ) {
- if ( this.length ) {
- data = jQuery.data( elem );
-
- if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
- attrs = elem.attributes;
- for ( ; i < attrs.length; i++ ) {
- name = attrs[i].name;
-
- if ( name.indexOf("data-") === 0 ) {
- name = jQuery.camelCase( name.slice(5) );
-
- dataAttr( elem, name, data[ name ] );
- }
- }
- jQuery._data( elem, "parsedAttrs", true );
- }
- }
-
- return data;
- }
-
- // Sets multiple values
- if ( typeof key === "object" ) {
- return this.each(function() {
- jQuery.data( this, key );
- });
- }
-
- return arguments.length > 1 ?
-
- // Sets one value
- this.each(function() {
- jQuery.data( this, key, value );
- }) :
-
- // Gets one value
- // Try to fetch any internally stored data first
- elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
- },
-
- removeData: function( key ) {
- return this.each(function() {
- jQuery.removeData( this, key );
- });
- }
-});
-
-function dataAttr( elem, key, data ) {
- // If nothing was found internally, try to fetch any
- // data from the HTML5 data-* attribute
- if ( data === undefined && elem.nodeType === 1 ) {
-
- var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
-
- data = elem.getAttribute( name );
-
- if ( typeof data === "string" ) {
- try {
- data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null :
- // Only convert to a number if it doesn't change the string
- +data + "" === data ? +data :
- rbrace.test( data ) ? jQuery.parseJSON( data ) :
- data;
- } catch( e ) {}
-
- // Make sure we set the data so it isn't changed later
- jQuery.data( elem, key, data );
-
- } else {
- data = undefined;
- }
- }
-
- return data;
-}
-
-// checks a cache object for emptiness
-function isEmptyDataObject( obj ) {
- var name;
- for ( name in obj ) {
-
- // if the public data object is empty, the private is still empty
- if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
- continue;
- }
- if ( name !== "toJSON" ) {
- return false;
- }
- }
-
- return true;
-}
-jQuery.extend({
- queue: function( elem, type, data ) {
- var queue;
-
- if ( elem ) {
- type = ( type || "fx" ) + "queue";
- queue = jQuery._data( elem, type );
-
- // Speed up dequeue by getting out quickly if this is just a lookup
- if ( data ) {
- if ( !queue || jQuery.isArray(data) ) {
- queue = jQuery._data( elem, type, jQuery.makeArray(data) );
- } else {
- queue.push( data );
- }
- }
- return queue || [];
- }
- },
-
- dequeue: function( elem, type ) {
- type = type || "fx";
-
- var queue = jQuery.queue( elem, type ),
- startLength = queue.length,
- fn = queue.shift(),
- hooks = jQuery._queueHooks( elem, type ),
- next = function() {
- jQuery.dequeue( elem, type );
- };
-
- // If the fx queue is dequeued, always remove the progress sentinel
- if ( fn === "inprogress" ) {
- fn = queue.shift();
- startLength--;
- }
-
- if ( fn ) {
-
- // Add a progress sentinel to prevent the fx queue from being
- // automatically dequeued
- if ( type === "fx" ) {
- queue.unshift( "inprogress" );
- }
-
- // clear up the last queue stop function
- delete hooks.stop;
- fn.call( elem, next, hooks );
- }
-
- if ( !startLength && hooks ) {
- hooks.empty.fire();
- }
- },
-
- // not intended for public consumption - generates a queueHooks object, or returns the current one
- _queueHooks: function( elem, type ) {
- var key = type + "queueHooks";
- return jQuery._data( elem, key ) || jQuery._data( elem, key, {
- empty: jQuery.Callbacks("once memory").add(function() {
- jQuery._removeData( elem, type + "queue" );
- jQuery._removeData( elem, key );
- })
- });
- }
-});
-
-jQuery.fn.extend({
- queue: function( type, data ) {
- var setter = 2;
-
- if ( typeof type !== "string" ) {
- data = type;
- type = "fx";
- setter--;
- }
-
- if ( arguments.length < setter ) {
- return jQuery.queue( this[0], type );
- }
-
- return data === undefined ?
- this :
- this.each(function() {
- var queue = jQuery.queue( this, type, data );
-
- // ensure a hooks for this queue
- jQuery._queueHooks( this, type );
-
- if ( type === "fx" && queue[0] !== "inprogress" ) {
- jQuery.dequeue( this, type );
- }
- });
- },
- dequeue: function( type ) {
- return this.each(function() {
- jQuery.dequeue( this, type );
- });
- },
- // Based off of the plugin by Clint Helfers, with permission.
- // http://blindsignals.com/index.php/2009/07/jquery-delay/
- delay: function( time, type ) {
- time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
- type = type || "fx";
-
- return this.queue( type, function( next, hooks ) {
- var timeout = setTimeout( next, time );
- hooks.stop = function() {
- clearTimeout( timeout );
- };
- });
- },
- clearQueue: function( type ) {
- return this.queue( type || "fx", [] );
- },
- // Get a promise resolved when queues of a certain type
- // are emptied (fx is the type by default)
- promise: function( type, obj ) {
- var tmp,
- count = 1,
- defer = jQuery.Deferred(),
- elements = this,
- i = this.length,
- resolve = function() {
- if ( !( --count ) ) {
- defer.resolveWith( elements, [ elements ] );
- }
- };
-
- if ( typeof type !== "string" ) {
- obj = type;
- type = undefined;
- }
- type = type || "fx";
-
- while( i-- ) {
- tmp = jQuery._data( elements[ i ], type + "queueHooks" );
- if ( tmp && tmp.empty ) {
- count++;
- tmp.empty.add( resolve );
- }
- }
- resolve();
- return defer.promise( obj );
- }
-});
-var nodeHook, boolHook,
- rclass = /[\t\r\n\f]/g,
- rreturn = /\r/g,
- rfocusable = /^(?:input|select|textarea|button|object)$/i,
- rclickable = /^(?:a|area)$/i,
- ruseDefault = /^(?:checked|selected)$/i,
- getSetAttribute = jQuery.support.getSetAttribute,
- getSetInput = jQuery.support.input;
-
-jQuery.fn.extend({
- attr: function( name, value ) {
- return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
- },
-
- removeAttr: function( name ) {
- return this.each(function() {
- jQuery.removeAttr( this, name );
- });
- },
-
- prop: function( name, value ) {
- return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
- },
-
- removeProp: function( name ) {
- name = jQuery.propFix[ name ] || name;
- return this.each(function() {
- // try/catch handles cases where IE balks (such as removing a property on window)
- try {
- this[ name ] = undefined;
- delete this[ name ];
- } catch( e ) {}
- });
- },
-
- addClass: function( value ) {
- var classes, elem, cur, clazz, j,
- i = 0,
- len = this.length,
- proceed = typeof value === "string" && value;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).addClass( value.call( this, j, this.className ) );
- });
- }
-
- if ( proceed ) {
- // The disjunction here is for better compressibility (see removeClass)
- classes = ( value || "" ).match( core_rnotwhite ) || [];
-
- for ( ; i < len; i++ ) {
- elem = this[ i ];
- cur = elem.nodeType === 1 && ( elem.className ?
- ( " " + elem.className + " " ).replace( rclass, " " ) :
- " "
- );
-
- if ( cur ) {
- j = 0;
- while ( (clazz = classes[j++]) ) {
- if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
- cur += clazz + " ";
- }
- }
- elem.className = jQuery.trim( cur );
-
- }
- }
- }
-
- return this;
- },
-
- removeClass: function( value ) {
- var classes, elem, cur, clazz, j,
- i = 0,
- len = this.length,
- proceed = arguments.length === 0 || typeof value === "string" && value;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).removeClass( value.call( this, j, this.className ) );
- });
- }
- if ( proceed ) {
- classes = ( value || "" ).match( core_rnotwhite ) || [];
-
- for ( ; i < len; i++ ) {
- elem = this[ i ];
- // This expression is here for better compressibility (see addClass)
- cur = elem.nodeType === 1 && ( elem.className ?
- ( " " + elem.className + " " ).replace( rclass, " " ) :
- ""
- );
-
- if ( cur ) {
- j = 0;
- while ( (clazz = classes[j++]) ) {
- // Remove *all* instances
- while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
- cur = cur.replace( " " + clazz + " ", " " );
- }
- }
- elem.className = value ? jQuery.trim( cur ) : "";
- }
- }
- }
-
- return this;
- },
-
- toggleClass: function( value, stateVal ) {
- var type = typeof value;
-
- if ( typeof stateVal === "boolean" && type === "string" ) {
- return stateVal ? this.addClass( value ) : this.removeClass( value );
- }
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( i ) {
- jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
- });
- }
-
- return this.each(function() {
- if ( type === "string" ) {
- // toggle individual class names
- var className,
- i = 0,
- self = jQuery( this ),
- classNames = value.match( core_rnotwhite ) || [];
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space separated list
- if ( self.hasClass( className ) ) {
- self.removeClass( className );
- } else {
- self.addClass( className );
- }
- }
-
- // Toggle whole class name
- } else if ( type === core_strundefined || type === "boolean" ) {
- if ( this.className ) {
- // store className if set
- jQuery._data( this, "__className__", this.className );
- }
-
- // If the element has a class name or if we're passed "false",
- // then remove the whole classname (if there was one, the above saved it).
- // Otherwise bring back whatever was previously saved (if anything),
- // falling back to the empty string if nothing was stored.
- this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
- }
- });
- },
-
- hasClass: function( selector ) {
- var className = " " + selector + " ",
- i = 0,
- l = this.length;
- for ( ; i < l; i++ ) {
- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
- return true;
- }
- }
-
- return false;
- },
-
- val: function( value ) {
- var ret, hooks, isFunction,
- elem = this[0];
-
- if ( !arguments.length ) {
- if ( elem ) {
- hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
-
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
- return ret;
- }
-
- ret = elem.value;
-
- return typeof ret === "string" ?
- // handle most common string cases
- ret.replace(rreturn, "") :
- // handle cases where value is null/undef or number
- ret == null ? "" : ret;
- }
-
- return;
- }
-
- isFunction = jQuery.isFunction( value );
-
- return this.each(function( i ) {
- var val;
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, jQuery( this ).val() );
- } else {
- val = value;
- }
-
- // Treat null/undefined as ""; convert numbers to string
- if ( val == null ) {
- val = "";
- } else if ( typeof val === "number" ) {
- val += "";
- } else if ( jQuery.isArray( val ) ) {
- val = jQuery.map(val, function ( value ) {
- return value == null ? "" : value + "";
- });
- }
-
- hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
-
- // If set returns undefined, fall back to normal setting
- if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
- this.value = val;
- }
- });
- }
-});
-
-jQuery.extend({
- valHooks: {
- option: {
- get: function( elem ) {
- // Use proper attribute retrieval(#6932, #12072)
- var val = jQuery.find.attr( elem, "value" );
- return val != null ?
- val :
- elem.text;
- }
- },
- select: {
- get: function( elem ) {
- var value, option,
- options = elem.options,
- index = elem.selectedIndex,
- one = elem.type === "select-one" || index < 0,
- values = one ? null : [],
- max = one ? index + 1 : options.length,
- i = index < 0 ?
- max :
- one ? index : 0;
-
- // Loop through all the selected options
- for ( ; i < max; i++ ) {
- option = options[ i ];
-
- // oldIE doesn't update selected after form reset (#2551)
- if ( ( option.selected || i === index ) &&
- // Don't return options that are disabled or in a disabled optgroup
- ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
- ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
-
- // Get the specific value for the option
- value = jQuery( option ).val();
-
- // We don't need an array for one selects
- if ( one ) {
- return value;
- }
-
- // Multi-Selects return an array
- values.push( value );
- }
- }
-
- return values;
- },
-
- set: function( elem, value ) {
- var optionSet, option,
- options = elem.options,
- values = jQuery.makeArray( value ),
- i = options.length;
-
- while ( i-- ) {
- option = options[ i ];
- if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
- optionSet = true;
- }
- }
-
- // force browsers to behave consistently when non-matching value is set
- if ( !optionSet ) {
- elem.selectedIndex = -1;
- }
- return values;
- }
- }
- },
-
- attr: function( elem, name, value ) {
- var hooks, ret,
- nType = elem.nodeType;
-
- // don't get/set attributes on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- // Fallback to prop when attributes are not supported
- if ( typeof elem.getAttribute === core_strundefined ) {
- return jQuery.prop( elem, name, value );
- }
-
- // All attributes are lowercase
- // Grab necessary hook if one is defined
- if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
- name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] ||
- ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
- }
-
- if ( value !== undefined ) {
-
- if ( value === null ) {
- jQuery.removeAttr( elem, name );
-
- } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- elem.setAttribute( name, value + "" );
- return value;
- }
-
- } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- ret = jQuery.find.attr( elem, name );
-
- // Non-existent attributes return null, we normalize to undefined
- return ret == null ?
- undefined :
- ret;
- }
- },
-
- removeAttr: function( elem, value ) {
- var name, propName,
- i = 0,
- attrNames = value && value.match( core_rnotwhite );
-
- if ( attrNames && elem.nodeType === 1 ) {
- while ( (name = attrNames[i++]) ) {
- propName = jQuery.propFix[ name ] || name;
-
- // Boolean attributes get special treatment (#10870)
- if ( jQuery.expr.match.bool.test( name ) ) {
- // Set corresponding property to false
- if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
- elem[ propName ] = false;
- // Support: IE<9
- // Also clear defaultChecked/defaultSelected (if appropriate)
- } else {
- elem[ jQuery.camelCase( "default-" + name ) ] =
- elem[ propName ] = false;
- }
-
- // See #9699 for explanation of this approach (setting first, then removal)
- } else {
- jQuery.attr( elem, name, "" );
- }
-
- elem.removeAttribute( getSetAttribute ? name : propName );
- }
- }
- },
-
- attrHooks: {
- type: {
- set: function( elem, value ) {
- if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
- // Setting the type on a radio button after the value resets the value in IE6-9
- // Reset value to default in case type is set after value during creation
- var val = elem.value;
- elem.setAttribute( "type", value );
- if ( val ) {
- elem.value = val;
- }
- return value;
- }
- }
- }
- },
-
- propFix: {
- "for": "htmlFor",
- "class": "className"
- },
-
- prop: function( elem, name, value ) {
- var ret, hooks, notxml,
- nType = elem.nodeType;
-
- // don't get/set properties on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- if ( notxml ) {
- // Fix name and attach hooks
- name = jQuery.propFix[ name ] || name;
- hooks = jQuery.propHooks[ name ];
- }
-
- if ( value !== undefined ) {
- return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
- ret :
- ( elem[ name ] = value );
-
- } else {
- return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
- ret :
- elem[ name ];
- }
- },
-
- propHooks: {
- tabIndex: {
- get: function( elem ) {
- // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
- // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
- // Use proper attribute retrieval(#12072)
- var tabindex = jQuery.find.attr( elem, "tabindex" );
-
- return tabindex ?
- parseInt( tabindex, 10 ) :
- rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
- 0 :
- -1;
- }
- }
- }
-});
-
-// Hooks for boolean attributes
-boolHook = {
- set: function( elem, value, name ) {
- if ( value === false ) {
- // Remove boolean attributes when set to false
- jQuery.removeAttr( elem, name );
- } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
- // IE<8 needs the *property* name
- elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
-
- // Use defaultChecked and defaultSelected for oldIE
- } else {
- elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
- }
-
- return name;
- }
-};
-jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
- var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
-
- jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
- function( elem, name, isXML ) {
- var fn = jQuery.expr.attrHandle[ name ],
- ret = isXML ?
- undefined :
- /* jshint eqeqeq: false */
- (jQuery.expr.attrHandle[ name ] = undefined) !=
- getter( elem, name, isXML ) ?
-
- name.toLowerCase() :
- null;
- jQuery.expr.attrHandle[ name ] = fn;
- return ret;
- } :
- function( elem, name, isXML ) {
- return isXML ?
- undefined :
- elem[ jQuery.camelCase( "default-" + name ) ] ?
- name.toLowerCase() :
- null;
- };
-});
-
-// fix oldIE attroperties
-if ( !getSetInput || !getSetAttribute ) {
- jQuery.attrHooks.value = {
- set: function( elem, value, name ) {
- if ( jQuery.nodeName( elem, "input" ) ) {
- // Does not return so that setAttribute is also used
- elem.defaultValue = value;
- } else {
- // Use nodeHook if defined (#1954); otherwise setAttribute is fine
- return nodeHook && nodeHook.set( elem, value, name );
- }
- }
- };
-}
-
-// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !getSetAttribute ) {
-
- // Use this for any attribute in IE6/7
- // This fixes almost every IE6/7 issue
- nodeHook = {
- set: function( elem, value, name ) {
- // Set the existing or create a new attribute node
- var ret = elem.getAttributeNode( name );
- if ( !ret ) {
- elem.setAttributeNode(
- (ret = elem.ownerDocument.createAttribute( name ))
- );
- }
-
- ret.value = value += "";
-
- // Break association with cloned elements by also using setAttribute (#9646)
- return name === "value" || value === elem.getAttribute( name ) ?
- value :
- undefined;
- }
- };
- jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords =
- // Some attributes are constructed with empty-string values when not defined
- function( elem, name, isXML ) {
- var ret;
- return isXML ?
- undefined :
- (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
- ret.value :
- null;
- };
- jQuery.valHooks.button = {
- get: function( elem, name ) {
- var ret = elem.getAttributeNode( name );
- return ret && ret.specified ?
- ret.value :
- undefined;
- },
- set: nodeHook.set
- };
-
- // Set contenteditable to false on removals(#10429)
- // Setting to empty string throws an error as an invalid value
- jQuery.attrHooks.contenteditable = {
- set: function( elem, value, name ) {
- nodeHook.set( elem, value === "" ? false : value, name );
- }
- };
-
- // Set width and height to auto instead of 0 on empty string( Bug #8150 )
- // This is for removals
- jQuery.each([ "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = {
- set: function( elem, value ) {
- if ( value === "" ) {
- elem.setAttribute( name, "auto" );
- return value;
- }
- }
- };
- });
-}
-
-
-// Some attributes require a special call on IE
-// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
-if ( !jQuery.support.hrefNormalized ) {
- // href/src property should get the full normalized URL (#10299/#12915)
- jQuery.each([ "href", "src" ], function( i, name ) {
- jQuery.propHooks[ name ] = {
- get: function( elem ) {
- return elem.getAttribute( name, 4 );
- }
- };
- });
-}
-
-if ( !jQuery.support.style ) {
- jQuery.attrHooks.style = {
- get: function( elem ) {
- // Return undefined in the case of empty string
- // Note: IE uppercases css property names, but if we were to .toLowerCase()
- // .cssText, that would destroy case senstitivity in URL's, like in "background"
- return elem.style.cssText || undefined;
- },
- set: function( elem, value ) {
- return ( elem.style.cssText = value + "" );
- }
- };
-}
-
-// Safari mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
-if ( !jQuery.support.optSelected ) {
- jQuery.propHooks.selected = {
- get: function( elem ) {
- var parent = elem.parentNode;
-
- if ( parent ) {
- parent.selectedIndex;
-
- // Make sure that it also works with optgroups, see #5701
- if ( parent.parentNode ) {
- parent.parentNode.selectedIndex;
- }
- }
- return null;
- }
- };
-}
-
-jQuery.each([
- "tabIndex",
- "readOnly",
- "maxLength",
- "cellSpacing",
- "cellPadding",
- "rowSpan",
- "colSpan",
- "useMap",
- "frameBorder",
- "contentEditable"
-], function() {
- jQuery.propFix[ this.toLowerCase() ] = this;
-});
-
-// IE6/7 call enctype encoding
-if ( !jQuery.support.enctype ) {
- jQuery.propFix.enctype = "encoding";
-}
-
-// Radios and checkboxes getter/setter
-jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- };
- if ( !jQuery.support.checkOn ) {
- jQuery.valHooks[ this ].get = function( elem ) {
- // Support: Webkit
- // "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- };
- }
-});
-var rformElems = /^(?:input|select|textarea)$/i,
- rkeyEvent = /^key/,
- rmouseEvent = /^(?:mouse|contextmenu)|click/,
- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
-
-function returnTrue() {
- return true;
-}
-
-function returnFalse() {
- return false;
-}
-
-function safeActiveElement() {
- try {
- return document.activeElement;
- } catch ( err ) { }
-}
-
-/*
- * Helper functions for managing events -- not part of the public interface.
- * Props to Dean Edwards' addEvent library for many of the ideas.
- */
-jQuery.event = {
-
- global: {},
-
- add: function( elem, types, handler, data, selector ) {
- var tmp, events, t, handleObjIn,
- special, eventHandle, handleObj,
- handlers, type, namespaces, origType,
- elemData = jQuery._data( elem );
-
- // Don't attach events to noData or text/comment nodes (but allow plain objects)
- if ( !elemData ) {
- return;
- }
-
- // Caller can pass in an object of custom data in lieu of the handler
- if ( handler.handler ) {
- handleObjIn = handler;
- handler = handleObjIn.handler;
- selector = handleObjIn.selector;
- }
-
- // Make sure that the handler has a unique ID, used to find/remove it later
- if ( !handler.guid ) {
- handler.guid = jQuery.guid++;
- }
-
- // Init the element's event structure and main handler, if this is the first
- if ( !(events = elemData.events) ) {
- events = elemData.events = {};
- }
- if ( !(eventHandle = elemData.handle) ) {
- eventHandle = elemData.handle = function( e ) {
- // Discard the second event of a jQuery.event.trigger() and
- // when an event is called after a page has unloaded
- return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
- jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
- undefined;
- };
- // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
- eventHandle.elem = elem;
- }
-
- // Handle multiple events separated by a space
- types = ( types || "" ).match( core_rnotwhite ) || [""];
- t = types.length;
- while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
-
- // There *must* be a type, no attaching namespace-only handlers
- if ( !type ) {
- continue;
- }
-
- // If event changes its type, use the special event handlers for the changed type
- special = jQuery.event.special[ type ] || {};
-
- // If selector defined, determine special event api type, otherwise given type
- type = ( selector ? special.delegateType : special.bindType ) || type;
-
- // Update special based on newly reset type
- special = jQuery.event.special[ type ] || {};
-
- // handleObj is passed to all event handlers
- handleObj = jQuery.extend({
- type: type,
- origType: origType,
- data: data,
- handler: handler,
- guid: handler.guid,
- selector: selector,
- needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
- namespace: namespaces.join(".")
- }, handleObjIn );
-
- // Init the event handler queue if we're the first
- if ( !(handlers = events[ type ]) ) {
- handlers = events[ type ] = [];
- handlers.delegateCount = 0;
-
- // Only use addEventListener/attachEvent if the special events handler returns false
- if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
- // Bind the global event handler to the element
- if ( elem.addEventListener ) {
- elem.addEventListener( type, eventHandle, false );
-
- } else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, eventHandle );
- }
- }
- }
-
- if ( special.add ) {
- special.add.call( elem, handleObj );
-
- if ( !handleObj.handler.guid ) {
- handleObj.handler.guid = handler.guid;
- }
- }
-
- // Add to the element's handler list, delegates in front
- if ( selector ) {
- handlers.splice( handlers.delegateCount++, 0, handleObj );
- } else {
- handlers.push( handleObj );
- }
-
- // Keep track of which events have ever been used, for event optimization
- jQuery.event.global[ type ] = true;
- }
-
- // Nullify elem to prevent memory leaks in IE
- elem = null;
- },
-
- // Detach an event or set of events from an element
- remove: function( elem, types, handler, selector, mappedTypes ) {
- var j, handleObj, tmp,
- origCount, t, events,
- special, handlers, type,
- namespaces, origType,
- elemData = jQuery.hasData( elem ) && jQuery._data( elem );
-
- if ( !elemData || !(events = elemData.events) ) {
- return;
- }
-
- // Once for each type.namespace in types; type may be omitted
- types = ( types || "" ).match( core_rnotwhite ) || [""];
- t = types.length;
- while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
-
- // Unbind all events (on this namespace, if provided) for the element
- if ( !type ) {
- for ( type in events ) {
- jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
- }
- continue;
- }
-
- special = jQuery.event.special[ type ] || {};
- type = ( selector ? special.delegateType : special.bindType ) || type;
- handlers = events[ type ] || [];
- tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
-
- // Remove matching events
- origCount = j = handlers.length;
- while ( j-- ) {
- handleObj = handlers[ j ];
-
- if ( ( mappedTypes || origType === handleObj.origType ) &&
- ( !handler || handler.guid === handleObj.guid ) &&
- ( !tmp || tmp.test( handleObj.namespace ) ) &&
- ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
- handlers.splice( j, 1 );
-
- if ( handleObj.selector ) {
- handlers.delegateCount--;
- }
- if ( special.remove ) {
- special.remove.call( elem, handleObj );
- }
- }
- }
-
- // Remove generic event handler if we removed something and no more handlers exist
- // (avoids potential for endless recursion during removal of special event handlers)
- if ( origCount && !handlers.length ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
- jQuery.removeEvent( elem, type, elemData.handle );
- }
-
- delete events[ type ];
- }
- }
-
- // Remove the expando if it's no longer used
- if ( jQuery.isEmptyObject( events ) ) {
- delete elemData.handle;
-
- // removeData also checks for emptiness and clears the expando if empty
- // so use it instead of delete
- jQuery._removeData( elem, "events" );
- }
- },
-
- trigger: function( event, data, elem, onlyHandlers ) {
- var handle, ontype, cur,
- bubbleType, special, tmp, i,
- eventPath = [ elem || document ],
- type = core_hasOwn.call( event, "type" ) ? event.type : event,
- namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
-
- cur = tmp = elem = elem || document;
-
- // Don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
-
- // focus/blur morphs to focusin/out; ensure we're not firing them right now
- if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
- return;
- }
-
- if ( type.indexOf(".") >= 0 ) {
- // Namespaced trigger; create a regexp to match event type in handle()
- namespaces = type.split(".");
- type = namespaces.shift();
- namespaces.sort();
- }
- ontype = type.indexOf(":") < 0 && "on" + type;
-
- // Caller can pass in a jQuery.Event object, Object, or just an event type string
- event = event[ jQuery.expando ] ?
- event :
- new jQuery.Event( type, typeof event === "object" && event );
-
- // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
- event.isTrigger = onlyHandlers ? 2 : 3;
- event.namespace = namespaces.join(".");
- event.namespace_re = event.namespace ?
- new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
- null;
-
- // Clean up the event in case it is being reused
- event.result = undefined;
- if ( !event.target ) {
- event.target = elem;
- }
-
- // Clone any incoming data and prepend the event, creating the handler arg list
- data = data == null ?
- [ event ] :
- jQuery.makeArray( data, [ event ] );
-
- // Allow special events to draw outside the lines
- special = jQuery.event.special[ type ] || {};
- if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
- return;
- }
-
- // Determine event propagation path in advance, per W3C events spec (#9951)
- // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
- if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
-
- bubbleType = special.delegateType || type;
- if ( !rfocusMorph.test( bubbleType + type ) ) {
- cur = cur.parentNode;
- }
- for ( ; cur; cur = cur.parentNode ) {
- eventPath.push( cur );
- tmp = cur;
- }
-
- // Only add window if we got to document (e.g., not plain obj or detached DOM)
- if ( tmp === (elem.ownerDocument || document) ) {
- eventPath.push( tmp.defaultView || tmp.parentWindow || window );
- }
- }
-
- // Fire handlers on the event path
- i = 0;
- while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
-
- event.type = i > 1 ?
- bubbleType :
- special.bindType || type;
-
- // jQuery handler
- handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
- if ( handle ) {
- handle.apply( cur, data );
- }
-
- // Native handler
- handle = ontype && cur[ ontype ];
- if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
- event.preventDefault();
- }
- }
- event.type = type;
-
- // If nobody prevented the default action, do it now
- if ( !onlyHandlers && !event.isDefaultPrevented() ) {
-
- if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
- jQuery.acceptData( elem ) ) {
-
- // Call a native DOM method on the target with the same name name as the event.
- // Can't use an .isFunction() check here because IE6/7 fails that test.
- // Don't do default actions on window, that's where global variables be (#6170)
- if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
-
- // Don't re-trigger an onFOO event when we call its FOO() method
- tmp = elem[ ontype ];
-
- if ( tmp ) {
- elem[ ontype ] = null;
- }
-
- // Prevent re-triggering of the same event, since we already bubbled it above
- jQuery.event.triggered = type;
- try {
- elem[ type ]();
- } catch ( e ) {
- // IE<9 dies on focus/blur to hidden element (#1486,#12518)
- // only reproducible on winXP IE8 native, not IE9 in IE8 mode
- }
- jQuery.event.triggered = undefined;
-
- if ( tmp ) {
- elem[ ontype ] = tmp;
- }
- }
- }
- }
-
- return event.result;
- },
-
- dispatch: function( event ) {
-
- // Make a writable jQuery.Event from the native event object
- event = jQuery.event.fix( event );
-
- var i, ret, handleObj, matched, j,
- handlerQueue = [],
- args = core_slice.call( arguments ),
- handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
- special = jQuery.event.special[ event.type ] || {};
-
- // Use the fix-ed jQuery.Event rather than the (read-only) native event
- args[0] = event;
- event.delegateTarget = this;
-
- // Call the preDispatch hook for the mapped type, and let it bail if desired
- if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
- return;
- }
-
- // Determine handlers
- handlerQueue = jQuery.event.handlers.call( this, event, handlers );
-
- // Run delegates first; they may want to stop propagation beneath us
- i = 0;
- while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
- event.currentTarget = matched.elem;
-
- j = 0;
- while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
-
- // Triggered event must either 1) have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
- if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
-
- event.handleObj = handleObj;
- event.data = handleObj.data;
-
- ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
- .apply( matched.elem, args );
-
- if ( ret !== undefined ) {
- if ( (event.result = ret) === false ) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- }
- }
-
- // Call the postDispatch hook for the mapped type
- if ( special.postDispatch ) {
- special.postDispatch.call( this, event );
- }
-
- return event.result;
- },
-
- handlers: function( event, handlers ) {
- var sel, handleObj, matches, i,
- handlerQueue = [],
- delegateCount = handlers.delegateCount,
- cur = event.target;
-
- // Find delegate handlers
- // Black-hole SVG