diff options
author | 2016-09-13 11:40:12 +0800 | |
---|---|---|
committer | 2016-09-13 11:41:53 +0800 | |
commit | b731e2f1dd0972409b136aebc7b463dd72c9cfad (patch) | |
tree | 5107d7d80c19ad8076c2c97c2b5ef8d1cf3ab903 /framework/src/onos/utils | |
parent | ee93993458266114c29271a481ef9ce7ce621b2a (diff) |
ONOSFW-171
O/S-SFC-ONOS scenario documentation
Change-Id: I51ae1cf736ea24ab6680f8edca1b2bf5dd598365
Signed-off-by: CNlucius <lukai1@huawei.com>
Diffstat (limited to 'framework/src/onos/utils')
325 files changed, 0 insertions, 47890 deletions
diff --git a/framework/src/onos/utils/catalyst/pom.xml b/framework/src/onos/utils/catalyst/pom.xml deleted file mode 100644 index 8a504bbd..00000000 --- a/framework/src/onos/utils/catalyst/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <parent> - <artifactId>onlab-utils</artifactId> - <groupId>org.onosproject</groupId> - <version>1.4.0-rc1</version> - </parent> - <modelVersion>4.0.0</modelVersion> - - <artifactId>utils.catalyst</artifactId> - <packaging>bundle</packaging> - - <description>ONLab catalyst dependency</description> - - <dependencies> - <dependency> - <groupId>io.atomix.catalyst</groupId> - <artifactId>catalyst-netty</artifactId> - <version>1.0.0-rc5</version> - </dependency> - - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-shade-plugin</artifactId> - <configuration> - <artifactSet> - <includes> - <include>io/atomix/catalyst/**</include> - </includes> - </artifactSet> - </configuration> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>shade</goal> - </goals> - </execution> - </executions> - </plugin> - - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <configuration> - <instructions> - <Export-Package> - io.atomix.catalyst.* - </Export-Package> - </instructions> - </configuration> - </plugin> - - </plugins> - </build> -</project>
\ No newline at end of file diff --git a/framework/src/onos/utils/catalyst/src/main/java/org/onlab/catalyst/OnlabCatalyst.java b/framework/src/onos/utils/catalyst/src/main/java/org/onlab/catalyst/OnlabCatalyst.java deleted file mode 100644 index c3ecc860..00000000 --- a/framework/src/onos/utils/catalyst/src/main/java/org/onlab/catalyst/OnlabCatalyst.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.onlab.catalyst; - -/** - * Created by admin on 11/24/15. - */ -public class OnlabCatalyst { -} diff --git a/framework/src/onos/utils/catalyst/src/main/java/org/onlab/catalyst/package-info.java b/framework/src/onos/utils/catalyst/src/main/java/org/onlab/catalyst/package-info.java deleted file mode 100644 index 1fdb9ea2..00000000 --- a/framework/src/onos/utils/catalyst/src/main/java/org/onlab/catalyst/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Created by admin on 11/24/15. - */ -package org.onlab.catalyst;
\ No newline at end of file diff --git a/framework/src/onos/utils/jdvue/bin/jdvue b/framework/src/onos/utils/jdvue/bin/jdvue deleted file mode 100755 index db9d164b..00000000 --- a/framework/src/onos/utils/jdvue/bin/jdvue +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -#------------------------------------------------------------------------------- -# Java Package Dependency viewer -# -# written by Thomas Vachuska -# -- Doobs -- -#------------------------------------------------------------------------------- - -JDVUE_ROOT=${JDVUE_ROOT:-$(dirname $0)/..} -cd $JDVUE_ROOT -VER=1.4.0-rc1 -JAR=$PWD/target/jdvue-${VER}.jar # start with the dev jar first -cd - >/dev/null - -# If the dev jar is not available, use one from .m2/repository -[ -f ${JAR} ] || JAR=~/.m2/repository/org/onlab/tools/jdvue/${VER}/jdvue-${VER}.jar - -# Assume default project to be the base-name of the argument or of current dir -name=$(basename ${1:-$PWD}) - -# If the -n option is specified use the next argument as the catalog name -[ "$1" = "-n" -a $# -ge 2 ] && name=$2 && shift 2 - -# Use the rest of the arguments as paths to scan for sources to build catalog -find "${@:-.}" -type f -name \*.java \ - | grep -v -E '/lost+found/|/target/|archetype-resources' \ - | xargs grep -E "^[ \t]*import .*;.*|^[ \t]*package .*;.*" \ - | tr -d '\r' > $name.db - -# Now run the Java Dependency Viewer jar on the catalog -java -jar ${JAR} $name && rm $name.db && open $name.html diff --git a/framework/src/onos/utils/jdvue/bin/jdvue-scan b/framework/src/onos/utils/jdvue/bin/jdvue-scan deleted file mode 100755 index 216c68d7..00000000 --- a/framework/src/onos/utils/jdvue/bin/jdvue-scan +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -#------------------------------------------------------------------------------- -# Java Package Dependency scanner -# -# written by Thomas Vachuska -# -- Doobs -- -#------------------------------------------------------------------------------- - -find "${@:-.}" -type f -name \*.java \ - | grep -v -E '/lost+found/|/target/' \ - | xargs grep -E "^[ \t]*import .*;.*|^[ \t]*package .*;.*" \ - | tr -d '\r' > jpd.db diff --git a/framework/src/onos/utils/jdvue/pom.xml b/framework/src/onos/utils/jdvue/pom.xml deleted file mode 100644 index 777eba3d..00000000 --- a/framework/src/onos/utils/jdvue/pom.xml +++ /dev/null @@ -1,108 +0,0 @@ -<?xml version="1.0"?> -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <prerequisites> - <maven>3.0.4</maven> - </prerequisites> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>jdvue</artifactId> - <packaging>jar</packaging> - - <description>Java Package Dependency & Analyzer</description> - - <properties> - <!-- FIXME skipping checkstyle for now --> - <checkstyle.skip>true</checkstyle.skip> - </properties> - - <dependencies> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava</artifactId> - <version>18.0</version> - </dependency> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava-testlib</artifactId> - <version>18.0</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-databind</artifactId> - <version>2.4.2</version> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-annotations</artifactId> - <version>2.4.2</version> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-junit</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.1</version> - <configuration> - <source>1.8</source> - <target>1.8</target> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-shade-plugin</artifactId> - <version>2.3</version> - <configuration> - <transformers> - <transformer - implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> - <mainClass>org.onlab.jdvue.DependencyViewer - </mainClass> - </transformer> - </transformers> - </configuration> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>shade</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - -</project> diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Catalog.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Catalog.java deleted file mode 100644 index 40cb99a3..00000000 --- a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Catalog.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - - -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Produces a package & source catalogue. - * - * @author Thomas Vachuska - */ -public class Catalog { - - private static final String PACKAGE = "package"; - private static final String IMPORT = "import"; - private static final String STATIC = "static"; - private static final String SRC_ROOT = "src/main/java/"; - private static final String WILDCARD = "\\.*$"; - - private final Map<String, JavaSource> sources = new HashMap<>(); - private final Map<String, JavaPackage> packages = new HashMap<>(); - private final Set<DependencyCycle> cycles = new HashSet<>(); - private final Set<Dependency> cycleSegments = new HashSet<>(); - private final Map<JavaPackage, Set<DependencyCycle>> packageCycles = new HashMap<>(); - private final Map<JavaPackage, Set<Dependency>> packageCycleSegments = new HashMap<>(); - - /** - * Loads the catalog from the specified catalog file. - * - * @param catalogPath catalog file path - * @throws IOException if unable to read the catalog file - */ - public void load(String catalogPath) throws IOException { - InputStream is = new FileInputStream(catalogPath); - BufferedReader br = new BufferedReader(new InputStreamReader(is)); - - String line; - while ((line = br.readLine()) != null) { - // Split the line into the two fields: path and pragmas - String fields[] = line.trim().split(":"); - if (fields.length <= 1) { - continue; - } - String path = fields[0]; - - // Now split the pragmas on whitespace and trim punctuation - String pragma[] = fields[1].trim().replaceAll("[;\n\r]", "").split("[\t ]"); - - // Locate (or create) Java source entity based on the path - JavaSource source = getOrCreateSource(path); - - // Now process the package or import statements - if (pragma[0].equals(PACKAGE)) { - processPackageDeclaration(source, pragma[1]); - - } else if (pragma[0].equals(IMPORT)) { - if (pragma[1].equals(STATIC)) { - processImportStatement(source, pragma[2]); - } else { - processImportStatement(source, pragma[1]); - } - } - } - } - - /** - * Analyzes the catalog by resolving imports and identifying circular - * package dependencies. - */ - public void analyze() { - resolveImports(); - findCircularDependencies(); - } - - /** - * Identifies circular package dependencies through what amounts to be a - * depth-first search rooted with each package. - */ - private void findCircularDependencies() { - cycles.clear(); - for (JavaPackage javaPackage : getPackages()) { - findCircularDependencies(javaPackage); - } - - cycleSegments.clear(); - packageCycles.clear(); - packageCycleSegments.clear(); - - for (DependencyCycle cycle : getCycles()) { - recordCycleForPackages(cycle); - cycleSegments.addAll(cycle.getCycleSegments()); - } - } - - /** - * Records the specified cycle into a set for each involved package. - * - * @param cycle cycle to record for involved packages - */ - private void recordCycleForPackages(DependencyCycle cycle) { - for (JavaPackage javaPackage : cycle.getCycle()) { - Set<DependencyCycle> cset = packageCycles.get(javaPackage); - if (cset == null) { - cset = new HashSet<>(); - packageCycles.put(javaPackage, cset); - } - cset.add(cycle); - - Set<Dependency> sset = packageCycleSegments.get(javaPackage); - if (sset == null) { - sset = new HashSet<>(); - packageCycleSegments.put(javaPackage, sset); - } - sset.addAll(cycle.getCycleSegments()); - } - } - - /** - * Identifies circular dependencies in which this package participates - * using depth-first search. - * - * @param javaPackage Java package to inspect for dependency cycles - */ - private void findCircularDependencies(JavaPackage javaPackage) { - // Setup a depth trace anchored at the given java package. - List<JavaPackage> trace = newTrace(new ArrayList<JavaPackage>(), javaPackage); - - Set<JavaPackage> searched = new HashSet<>(); - searchDependencies(javaPackage, trace, searched); - } - - /** - * Generates a new trace using the previous one and a new element - * - * @param trace old search trace - * @param javaPackage package to add to the trace - * @return new search trace - */ - private List<JavaPackage> newTrace(List<JavaPackage> trace, - JavaPackage javaPackage) { - List<JavaPackage> newTrace = new ArrayList<>(trace); - newTrace.add(javaPackage); - return newTrace; - } - - - /** - * Recursive depth-first search through dependency tree - * - * @param javaPackage java package being searched currently - * @param trace search trace - * @param searched set of java packages already searched - */ - private void searchDependencies(JavaPackage javaPackage, - List<JavaPackage> trace, - Set<JavaPackage> searched) { - if (!searched.contains(javaPackage)) { - searched.add(javaPackage); - for (JavaPackage dependency : javaPackage.getDependencies()) { - if (trace.contains(dependency)) { - cycles.add(new DependencyCycle(trace, dependency)); - } else { - searchDependencies(dependency, newTrace(trace, dependency), searched); - } - } - } - } - - /** - * Resolves import names of Java sources into imports of entities known - * to this catalog. All other import names will be ignored. - */ - private void resolveImports() { - for (JavaPackage javaPackage : getPackages()) { - Set<JavaPackage> dependencies = new HashSet<>(); - for (JavaSource source : javaPackage.getSources()) { - Set<JavaEntity> imports = resolveImports(source); - source.setImports(imports); - dependencies.addAll(importedPackages(imports)); - } - javaPackage.setDependencies(dependencies); - } - } - - /** - * Produces a set of imported Java packages from the specified set of - * Java source entities. - * - * @param imports list of imported Java source entities - * @return list of imported Java packages - */ - private Set<JavaPackage> importedPackages(Set<JavaEntity> imports) { - Set<JavaPackage> packages = new HashSet<>(); - for (JavaEntity entity : imports) { - packages.add(entity instanceof JavaPackage ? (JavaPackage) entity : - ((JavaSource) entity).getPackage()); - } - return packages; - } - - /** - * Resolves import names of the specified Java source into imports of - * entities known to this catalog. All other import names will be ignored. - * - * @param source Java source - * @return list of resolved imports - */ - private Set<JavaEntity> resolveImports(JavaSource source) { - Set<JavaEntity> imports = new HashSet<>(); - for (String importName : source.getImportNames()) { - JavaEntity entity = importName.matches(WILDCARD) ? - getPackage(importName.replaceAll(WILDCARD, "")) : - getSource(importName); - if (entity != null) { - imports.add(entity); - } - } - return imports; - } - - /** - * Returns either an existing or a newly created Java package. - * - * @param packageName Java package name - * @return Java package - */ - private JavaPackage getOrCreatePackage(String packageName) { - JavaPackage javaPackage = packages.get(packageName); - if (javaPackage == null) { - javaPackage = new JavaPackage(packageName); - packages.put(packageName, javaPackage); - } - return javaPackage; - } - - /** - * Returns either an existing or a newly created Java source. - * - * @param path Java source path - * @return Java source - */ - private JavaSource getOrCreateSource(String path) { - String name = nameFromPath(path); - JavaSource source = sources.get(name); - if (source == null) { - source = new JavaSource(name, path); - sources.put(name, source); - } - return source; - } - - /** - * Extracts a fully qualified source class name from the given path. - * <p/> - * For now, this implementation assumes standard Maven source structure - * and thus will look for start of package name under 'src/main/java/'. - * If it will not find such a prefix, it will simply return the path as - * the name. - * - * @param path source path - * @return source name - */ - private String nameFromPath(String path) { - int i = path.indexOf(SRC_ROOT); - String name = i < 0 ? path : path.substring(i + SRC_ROOT.length()); - return name.replaceAll("\\.java$", "").replace("/", "."); - } - - /** - * Processes the package declaration pragma for the given source. - * - * @param source Java source - * @param packageName Java package name - */ - private void processPackageDeclaration(JavaSource source, String packageName) { - JavaPackage javaPackage = getOrCreatePackage(packageName); - source.setPackage(javaPackage); - javaPackage.addSource(source); - } - - /** - * Processes the import pragma for the given source. - * - * @param source Java source - * @param name name of the Java entity being imported (class or package) - */ - private void processImportStatement(JavaSource source, String name) { - source.addImportName(name); - } - - /** - * Returns the collection of java sources. - * - * @return collection of java sources - */ - public Collection<JavaSource> getSources() { - return Collections.unmodifiableCollection(sources.values()); - } - - /** - * Returns the Java source with the specified name. - * - * @param name Java source name - * @return Java source - */ - public JavaSource getSource(String name) { - return sources.get(name); - } - - /** - * Returns the collection of all Java packages. - * - * @return collection of java packages - */ - public Collection<JavaPackage> getPackages() { - return Collections.unmodifiableCollection(packages.values()); - } - - /** - * Returns the set of all Java package dependency cycles. - * - * @return set of dependency cycles - */ - public Set<DependencyCycle> getCycles() { - return Collections.unmodifiableSet(cycles); - } - - /** - * Returns the set of all Java package dependency cycle segments. - * - * @return set of dependency cycle segments - */ - public Set<Dependency> getCycleSegments() { - return Collections.unmodifiableSet(cycleSegments); - } - - /** - * Returns the set of dependency cycles which involve the specified package. - * - * @param javaPackage java package - * @return set of dependency cycles - */ - public Set<DependencyCycle> getPackageCycles(JavaPackage javaPackage) { - Set<DependencyCycle> set = packageCycles.get(javaPackage); - return Collections.unmodifiableSet(set == null ? new HashSet<DependencyCycle>() : set); - } - - /** - * Returns the set of dependency cycle segments which involve the specified package. - * - * @param javaPackage java package - * @return set of dependency cycle segments - */ - public Set<Dependency> getPackageCycleSegments(JavaPackage javaPackage) { - Set<Dependency> set = packageCycleSegments.get(javaPackage); - return Collections.unmodifiableSet(set == null ? new HashSet<Dependency>() : set); - } - - /** - * Returns the Java package with the specified name. - * - * @param name Java package name - * @return Java package - */ - public JavaPackage getPackage(String name) { - return packages.get(name); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("packages", packages.size()) - .add("sources", sources.size()) - .add("cycles", cycles.size()) - .add("cycleSegments", cycleSegments.size()).toString(); - } - -} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Dependency.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Dependency.java deleted file mode 100644 index 21fae479..00000000 --- a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Dependency.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Abstraction of a dependency segment. - * - * @author Thomas Vachuska - */ -public class Dependency { - - private final JavaPackage source; - private final JavaPackage target; - - /** - * Creates a dependency from the specified source on the given target. - * - * @param source source of the dependency - * @param target target of the dependency - */ - public Dependency(JavaPackage source, JavaPackage target) { - this.source = source; - this.target = target; - } - - /** - * Returns the dependency source. - * - * @return source Java package - */ - public JavaPackage getSource() { - return source; - } - - /** - * Returns the dependency target. - * - * @return target Java package - */ - public JavaPackage getTarget() { - return target; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Dependency) { - Dependency that = (Dependency) obj; - return Objects.equals(source, that.source) && - Objects.equals(target, that.target); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(source, target); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("source", source).add("target", target).toString(); - } - -} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyCycle.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyCycle.java deleted file mode 100644 index 0fc761d4..00000000 --- a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyCycle.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Simple representation of a Java package dependency cycle. - */ -public class DependencyCycle { - - private final List<JavaPackage> cycle; - - /** - * Creates a normalized dependency cycle represented by the specified list - * of Java packages, which are expected to be given in order of dependency. - * List is assumed to be non-empty. - * - * @param cycle list of Java packages in the dependency cycle - * @param cause Java package that caused the cycle - */ - DependencyCycle(List<JavaPackage> cycle, JavaPackage cause) { - this.cycle = normalize(cycle, cause); - } - - /** - * Produces a normalized dependency cycle list. Normalization is performed - * by rotating the list so that the package with the least lexicographic - * name is at the start of the list. - * - * @param cycle list of Java packages in the dependency cycle - * @param cause Java package that caused the cycle - * @return normalized cycle - */ - private List<JavaPackage> normalize(List<JavaPackage> cycle, JavaPackage cause) { - int start = cycle.indexOf(cause); - List<JavaPackage> clone = new ArrayList<>(cycle.subList(start, cycle.size())); - int leastIndex = findIndexOfLeastName(clone); - Collections.rotate(clone, -leastIndex); - return Collections.unmodifiableList(clone); - } - - /** - * Returns the index of the Java package with the least name. - * - * @param cycle list of Java packages in the dependency cycle - * @return index of the least Java package name - */ - private int findIndexOfLeastName(List<JavaPackage> cycle) { - int leastIndex = 0; - String leastName = cycle.get(leastIndex).name(); - for (int i = 1, n = cycle.size(); i < n; i++) { - JavaPackage javaPackage = cycle.get(i); - if (leastName.compareTo(javaPackage.name()) > 0) { - leastIndex = i; - leastName = javaPackage.name(); - } - } - return leastIndex; - } - - /** - * Returns the normalized Java package dependency cycle - * - * @return list of packages in the dependency cycle - */ - public List<JavaPackage> getCycle() { - return cycle; - } - - /** - * Returns the dependency cycle in form of individual dependencies. - * - * @return list of dependencies forming the cycle - */ - public List<Dependency> getCycleSegments() { - List<Dependency> dependencies = new ArrayList<>(); - for (int i = 0, n = cycle.size(); i < n; i++) { - dependencies.add(new Dependency(cycle.get(i), cycle.get(i < n - 1 ? i + 1 : 0))); - } - return dependencies; - } - - @Override - public boolean equals(Object o) { - if (o instanceof DependencyCycle) { - DependencyCycle that = (DependencyCycle) o; - return Objects.equals(cycle, that.cycle); - } - return false; - } - - @Override - public int hashCode() { - return cycle.hashCode(); - } - - @Override - public String toString() { - return toStringHelper(this).add("cycle", cycle).toString(); - } - - public String toShortString() { - StringBuilder sb = new StringBuilder("["); - for (JavaPackage javaPackage : cycle) { - sb.append(javaPackage.name()).append(", "); - } - if (sb.length() > 1) { - sb.delete(sb.length() - 2, sb.length()); - } - sb.append("]"); - return sb.toString(); - } - -} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java deleted file mode 100644 index 32e9ef1c..00000000 --- a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import java.io.BufferedReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Set; - -/** - * Generator of a self-contained HTML file which serves as a GUI for - * visualizing Java package dependencies carried in the supplied catalog. - * - * The HTML file is an adaptation of D3.js Hierarchical Edge Bundling as - * shown at http://bl.ocks.org/mbostock/7607999. - * - * @author Thomas Vachuska - */ -public class DependencyViewer { - - private static final String JPD_EXT = ".db"; - private static final String HTML_EXT = ".html"; - - private static final String INDEX = "index.html"; - private static final String D3JS = "d3.v3.min.js"; - - private static final String TITLE_PLACEHOLDER = "TITLE_PLACEHOLDER"; - private static final String D3JS_PLACEHOLDER = "D3JS_PLACEHOLDER"; - private static final String DATA_PLACEHOLDER = "DATA_PLACEHOLDER"; - - private final Catalog catalog; - - /** - * Creates a Java package dependency viewer. - * - * @param catalog dependency catalog - */ - public DependencyViewer(Catalog catalog) { - this.catalog = catalog; - } - - /** - * Main program entry point. - * - * @param args command line arguments - */ - public static void main(String[] args) { - Catalog cat = new Catalog(); - DependencyViewer viewer = new DependencyViewer(cat); - try { - String path = args[0]; - cat.load(path + JPD_EXT); - cat.analyze(); - - System.err.println(cat); - viewer.dumpLongestCycle(cat); - viewer.writeHTMLFile(path); - } catch (IOException e) { - System.err.println("Unable to process catalog: " + e.getMessage()); - } - } - - /** - * Prints out the longest cycle; just for kicks. - * @param cat catalog - */ - private void dumpLongestCycle(Catalog cat) { - DependencyCycle longest = null; - for (DependencyCycle cycle : cat.getCycles()) { - if (longest == null || longest.getCycleSegments().size() < cycle.getCycleSegments().size()) { - longest = cycle; - } - } - - if (longest != null) { - for (Dependency dependency : longest.getCycleSegments()) { - System.out.println(dependency); - } - } - } - - /** - * Writes the HTML catalog file for the given viewer. - * - * @param path base file path - * @throws IOException if issues encountered writing the HTML file - */ - public void writeHTMLFile(String path) throws IOException { - String index = slurp(getClass().getResourceAsStream(INDEX)); - String d3js = slurp(getClass().getResourceAsStream(D3JS)); - - FileWriter fw = new FileWriter(path + HTML_EXT); - ObjectWriter writer = new ObjectMapper().writer(); // .writerWithDefaultPrettyPrinter(); - fw.write(index.replace(TITLE_PLACEHOLDER, path) - .replace(D3JS_PLACEHOLDER, d3js) - .replace(DATA_PLACEHOLDER, writer.writeValueAsString(toJson()))); - fw.close(); - } - - /** - * Slurps the specified input stream into a string. - * - * @param stream input stream to be read - * @return string containing the contents of the input stream - * @throws IOException if issues encountered reading from the stream - */ - static String slurp(InputStream stream) throws IOException { - StringBuilder sb = new StringBuilder(); - BufferedReader br = new BufferedReader(new InputStreamReader(stream)); - String line; - while ((line = br.readLine()) != null) { - sb.append(line).append(System.lineSeparator()); - } - br.close(); - return sb.toString(); - } - - // Produces a JSON structure designed to drive the hierarchical visual - // representation of Java package dependencies and any dependency cycles - private JsonNode toJson() { - ObjectMapper mapper = new ObjectMapper(); - ObjectNode root = mapper.createObjectNode(); - root.put("packages", jsonPackages(mapper)); - root.put("cycleSegments", jsonCycleSegments(mapper, catalog.getCycleSegments())); - root.put("summary", jsonSummary(mapper)); - return root; - } - - // Produces a JSON summary of dependencies - private JsonNode jsonSummary(ObjectMapper mapper) { - ObjectNode summary = mapper.createObjectNode(); - summary.put("packages", catalog.getPackages().size()); - summary.put("sources", catalog.getSources().size()); - summary.put("cycles", catalog.getCycles().size()); - summary.put("cycleSegments", catalog.getCycleSegments().size()); - return summary; - } - - // Produces a JSON structure with package dependency data - private JsonNode jsonPackages(ObjectMapper mapper) { - ArrayNode packages = mapper.createArrayNode(); - for (JavaPackage javaPackage : catalog.getPackages()) { - packages.add(json(mapper, javaPackage)); - } - return packages; - } - - // Produces a JSON structure with all cyclic segments - private JsonNode jsonCycleSegments(ObjectMapper mapper, - Set<Dependency> segments) { - ObjectNode cyclicSegments = mapper.createObjectNode(); - for (Dependency dependency : segments) { - String s = dependency.getSource().name(); - String t = dependency.getTarget().name(); - cyclicSegments.put(t + "-" + s, - mapper.createObjectNode().put("s", s).put("t", t)); - } - return cyclicSegments; - } - - // Produces a JSON object structure describing the specified Java package. - private JsonNode json(ObjectMapper mapper, JavaPackage javaPackage) { - ObjectNode node = mapper.createObjectNode(); - - ArrayNode imports = mapper.createArrayNode(); - for (JavaPackage dependency : javaPackage.getDependencies()) { - imports.add(dependency.name()); - } - - Set<DependencyCycle> packageCycles = catalog.getPackageCycles(javaPackage); - Set<Dependency> packageCycleSegments = catalog.getPackageCycleSegments(javaPackage); - - node.put("name", javaPackage.name()); - node.put("size", javaPackage.getSources().size()); - node.put("imports", imports); - node.put("cycleSegments", jsonCycleSegments(mapper, packageCycleSegments)); - node.put("cycleCount", packageCycles.size()); - node.put("cycleSegmentCount", packageCycleSegments.size()); - return node; - } - -} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaEntity.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaEntity.java deleted file mode 100644 index e74bdc60..00000000 --- a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaEntity.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import java.util.Objects; - -/** - * Abstraction of a Java source entity. - */ -public abstract class JavaEntity { - - private final String name; - - /** - * Creates a new Java source entity with the given name. - * - * @param name source entity name - */ - JavaEntity(String name) { - this.name = name; - } - - /** - * Returns the Java source entity name. - * - * @return source entity name - */ - public String name() { - return name; - } - - @Override - public boolean equals(Object o) { - if (o instanceof JavaEntity) { - JavaEntity that = (JavaEntity) o; - return getClass().equals(that.getClass()) && - Objects.equals(name, that.name); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(name); - } -} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaPackage.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaPackage.java deleted file mode 100644 index a15cb4d3..00000000 --- a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaPackage.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Simple abstraction of a Java package for the purpose of tracking - * dependencies and requirements. - * - * @author Thomas Vachuska - */ -public class JavaPackage extends JavaEntity { - - private final Set<JavaSource> sources = new HashSet<>(); - private Set<JavaPackage> dependencies; - - /** - * Creates a new Java package. - * - * @param name java package file name - */ - JavaPackage(String name) { - super(name); - } - - /** - * Returns the set of sources contained in this Java package. - * - * @return set of Java sources - */ - public Set<JavaSource> getSources() { - return Collections.unmodifiableSet(sources); - } - - /** - * Adds the specified Java source to the package. Only possible if the - * Java package of the source is the same as this Java package. - * - * @param source Java source to be added - */ - void addSource(JavaSource source) { - if (source.getPackage().equals(this)) { - sources.add(source); - } - } - - /** - * Returns the set of packages directly required by this package. - * - * @return set of Java package dependencies - */ - Set<JavaPackage> getDependencies() { - return dependencies; - } - - /** - * Sets the set of resolved Java packages on which this package dependens. - * - * @param dependencies set of resolved Java packages - */ - void setDependencies(Set<JavaPackage> dependencies) { - if (this.dependencies == null) { - this.dependencies = Collections.unmodifiableSet(new HashSet<>(dependencies)); - } - } - - @Override - public String toString() { - return toStringHelper(this) - .add("name", name()) - .add("sources", sources.size()) - .add("dependencies", (dependencies != null ? dependencies.size() : 0)) - .toString(); - } - -} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaSource.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaSource.java deleted file mode 100644 index 1376cfee..00000000 --- a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaSource.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import java.util.*; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Simple abstraction of a Java source file for the purpose of tracking - * dependencies and requirements. - * - * @author Thomas Vachuska - */ -public class JavaSource extends JavaEntity { - - private String path; - private JavaPackage javaPackage; - - private final Set<String> importNames = new HashSet<>(); - private Set<JavaEntity> imports; - - /** - * Creates a new Java source entity. - * - * @param name java source file name - * @param path source file path - */ - JavaSource(String name, String path) { - super(name); - this.path = path; - } - - /** - * Returns the Java package for this Java source. - * - * @return Java package - */ - public JavaPackage getPackage() { - return javaPackage; - } - - /** - * Sets the Java package for this Java source. - * - * @param javaPackage Java package - */ - void setPackage(JavaPackage javaPackage) { - if (this.javaPackage == null) { - this.javaPackage = javaPackage; - } - } - - /** - * Returns the set of resolved imports for this Java source - * - * @return set of imports - */ - public Set<JavaEntity> getImports() { - return imports; - } - - /** - * Sets the set of resolved imported Java entities for this source. - * - * @param imports set of resolved Java entities imported by this source - */ - void setImports(Set<JavaEntity> imports) { - if (this.imports == null) { - this.imports = Collections.unmodifiableSet(new HashSet<>(imports)); - } - } - - /** - * Adds a name of an imported, but unresolved, Java entity name. - * - * @param name name of an imported Java entity - */ - void addImportName(String name) { - importNames.add(name); - } - - /** - * Returns the set of imported, but unresolved, Java entity names. - * - * @return set of imported Java entity names - */ - Set<String> getImportNames() { - return importNames; - } - - @Override - public String toString() { - return toStringHelper(this) - .add("name", name()) - .add("javaPackage", (javaPackage != null ? javaPackage.name() : "")) - .add("importNames", importNames.size()) - .add("imports", (imports != null ? imports.size() : 0)) - .toString(); - } - -} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/package-info.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/package-info.java deleted file mode 100644 index 2f77ef24..00000000 --- a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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. - */ - -/** - * Utility to analyze Java package dependencies. - */ -package org.onlab.jdvue;
\ No newline at end of file diff --git a/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/d3.v3.min.js b/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/d3.v3.min.js deleted file mode 100644 index 4895e91b..00000000 --- a/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/d3.v3.min.js +++ /dev/null @@ -1,5 +0,0 @@ -!function(){function n(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function t(n){return null!=n&&!isNaN(n)}function e(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function r(n){return n.length}function u(n){for(var t=1;n*t%1;)t*=10;return t}function i(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function o(){}function a(n){return ia+n in this}function c(n){return n=ia+n,n in this&&delete this[n]}function s(){var n=[];return this.forEach(function(t){n.push(t)}),n}function l(){var n=0;for(var t in this)t.charCodeAt(0)===oa&&++n;return n}function f(){for(var n in this)if(n.charCodeAt(0)===oa)return!1;return!0}function h(){}function g(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function p(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=aa.length;r>e;++e){var u=aa[e]+t;if(u in n)return u}}function v(){}function d(){}function m(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new o;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function y(){Zo.event.preventDefault()}function x(){for(var n,t=Zo.event;n=t.sourceEvent;)t=n;return t}function M(n){for(var t=new d,e=0,r=arguments.length;++e<r;)t[arguments[e]]=m(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=Zo.event;u.target=n,Zo.event=u,t[u.type].apply(e,r)}finally{Zo.event=i}}},t}function _(n){return sa(n,pa),n}function b(n){return"function"==typeof n?n:function(){return la(n,this)}}function w(n){return"function"==typeof n?n:function(){return fa(n,this)}}function S(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=Zo.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function k(n){return n.trim().replace(/\s+/g," ")}function E(n){return new RegExp("(?:^|\\s+)"+Zo.requote(n)+"(?:\\s+|$)","g")}function A(n){return(n+"").trim().split(/^|\s+/)}function C(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=A(n).map(N);var u=n.length;return"function"==typeof t?r:e}function N(n){var t=E(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",k(u+" "+n))):e.setAttribute("class",k(u.replace(t," ")))}}function z(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function L(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function T(n){return"function"==typeof n?n:(n=Zo.ns.qualify(n)).local?function(){return this.ownerDocument.createElementNS(n.space,n.local)}:function(){return this.ownerDocument.createElementNS(this.namespaceURI,n)}}function q(n){return{__data__:n}}function R(n){return function(){return ga(this,n)}}function D(t){return arguments.length||(t=n),function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}}function P(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function U(n){return sa(n,da),n}function j(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function H(){var n=this.__transition__;n&&++n.active}function F(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,Xo(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+Zo.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=O;a>0&&(n=n.substring(0,a));var s=ya.get(n);return s&&(n=s,c=Y),a?t?u:r:t?v:i}function O(n,t){return function(e){var r=Zo.event;Zo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{Zo.event=r}}}function Y(n,t){var e=O(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function I(){var n=".dragsuppress-"+ ++Ma,t="click"+n,e=Zo.select(Wo).on("touchmove"+n,y).on("dragstart"+n,y).on("selectstart"+n,y);if(xa){var r=Bo.style,u=r[xa];r[xa]="none"}return function(i){function o(){e.on(t,null)}e.on(n,null),xa&&(r[xa]=u),i&&(e.on(t,function(){y(),o()},!0),setTimeout(o,0))}}function Z(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>_a&&(Wo.scrollX||Wo.scrollY)){e=Zo.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var u=e[0][0].getScreenCTM();_a=!(u.f||u.e),e.remove()}return _a?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}function V(){return Zo.event.changedTouches[0].identifier}function X(){return Zo.event.target}function $(){return Wo}function B(n){return n>0?1:0>n?-1:0}function W(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function J(n){return n>1?0:-1>n?ba:Math.acos(n)}function G(n){return n>1?Sa:-1>n?-Sa:Math.asin(n)}function K(n){return((n=Math.exp(n))-1/n)/2}function Q(n){return((n=Math.exp(n))+1/n)/2}function nt(n){return((n=Math.exp(2*n))-1)/(n+1)}function tt(n){return(n=Math.sin(n/2))*n}function et(){}function rt(n,t,e){return this instanceof rt?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof rt?new rt(n.h,n.s,n.l):mt(""+n,yt,rt):new rt(n,t,e)}function ut(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new gt(u(n+120),u(n),u(n-120))}function it(n,t,e){return this instanceof it?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof it?new it(n.h,n.c,n.l):n instanceof at?st(n.l,n.a,n.b):st((n=xt((n=Zo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new it(n,t,e)}function ot(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new at(e,Math.cos(n*=Aa)*t,Math.sin(n)*t)}function at(n,t,e){return this instanceof at?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof at?new at(n.l,n.a,n.b):n instanceof it?ot(n.l,n.c,n.h):xt((n=gt(n)).r,n.g,n.b):new at(n,t,e)}function ct(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=lt(u)*ja,r=lt(r)*Ha,i=lt(i)*Fa,new gt(ht(3.2404542*u-1.5371385*r-.4985314*i),ht(-.969266*u+1.8760108*r+.041556*i),ht(.0556434*u-.2040259*r+1.0572252*i))}function st(n,t,e){return n>0?new it(Math.atan2(e,t)*Ca,Math.sqrt(t*t+e*e),n):new it(0/0,0/0,n)}function lt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function ft(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function ht(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function gt(n,t,e){return this instanceof gt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof gt?new gt(n.r,n.g,n.b):mt(""+n,gt,ut):new gt(n,t,e)}function pt(n){return new gt(n>>16,255&n>>8,255&n)}function vt(n){return pt(n)+""}function dt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function mt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(_t(u[0]),_t(u[1]),_t(u[2]))}return(i=Ia.get(n))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.substring(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function yt(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new rt(r,u,c)}function xt(n,t,e){n=Mt(n),t=Mt(t),e=Mt(e);var r=ft((.4124564*n+.3575761*t+.1804375*e)/ja),u=ft((.2126729*n+.7151522*t+.072175*e)/Ha),i=ft((.0193339*n+.119192*t+.9503041*e)/Fa);return at(116*u-16,500*(r-u),200*(u-i))}function Mt(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function _t(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function bt(n){return"function"==typeof n?n:function(){return n}}function wt(n){return n}function St(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),kt(t,e,n,r)}}function kt(n,t,e,r){function u(){var n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return o.error.call(i,r),void 0}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=Zo.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,s=null;return!Wo.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=Zo.event;Zo.event=n;try{o.progress.call(i,c)}finally{Zo.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(s=n,i):s},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(Xo(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var l in a)c.setRequestHeader(l,a[l]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=s&&(c.responseType=s),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},Zo.rebind(i,o,"on"),null==r?i:i.get(Et(r))}function Et(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function At(){var n=Ct(),t=Nt()-n;t>24?(isFinite(t)&&(clearTimeout($a),$a=setTimeout(At,t)),Xa=0):(Xa=1,Wa(At))}function Ct(){var n=Date.now();for(Ba=Za;Ba;)n>=Ba.t&&(Ba.f=Ba.c(n-Ba.t)),Ba=Ba.n;return n}function Nt(){for(var n,t=Za,e=1/0;t;)t.f?t=n?n.n=t.n:Za=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Va=n,e}function zt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Lt(n,t){var e=Math.pow(10,3*ua(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Tt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r?function(n){for(var t=n.length,u=[],i=0,o=r[0];t>0&&o>0;)u.push(n.substring(t-=o,t+o)),o=r[i=(i+1)%r.length];return u.reverse().join(e)}:wt;return function(n){var e=Ga.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"",c=e[4]||"",s=e[5],l=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1;switch(h&&(h=+h.substring(1)),(s||"0"===r&&"="===o)&&(s=r="0",o="=",f&&(l-=Math.floor((l-1)/4))),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=Ka.get(g)||qt;var y=s&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):a;if(0>p){var c=Zo.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x=n.lastIndexOf("."),M=0>x?n:n.substring(0,x),_=0>x?"":t+n.substring(x+1);!s&&f&&(M=i(M));var b=v.length+M.length+_.length+(y?0:u.length),w=l>b?new Array(b=l-b+1).join(r):"";return y&&(M=i(w+M)),u+=v,n=M+_,("<"===o?u+n+w:">"===o?w+u+n:"^"===o?w.substring(0,b>>=1)+u+n+w.substring(b):u+(y?n:w+n))+e}}}function qt(n){return n+""}function Rt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Dt(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new nc(e-1)),1),e}function i(n,e){return t(n=new nc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{nc=Rt;var r=new Rt;return r._=n,o(r,t,e)}finally{nc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Pt(n);return c.floor=c,c.round=Pt(r),c.ceil=Pt(u),c.offset=Pt(i),c.range=a,n}function Pt(n){return function(t,e){try{nc=Rt;var r=new Rt;return r._=t,n(r,e)._}finally{nc=Date}}}function Ut(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.substring(c,a)),null!=(u=ec[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=C[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.substring(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&nc!==Rt,o=new(i?Rt:nc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+Math.floor(r.Z/100),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,s=e.length;c>a;){if(r>=s)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=N[o in ec?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){b.lastIndex=0;var r=b.exec(t.substring(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){M.lastIndex=0;var r=M.exec(t.substring(e));return r?(n.w=_.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.substring(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.substring(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,C.c.toString(),t,r)}function c(n,t,r){return e(n,C.x.toString(),t,r)}function s(n,t,r){return e(n,C.X.toString(),t,r)}function l(n,t,e){var r=x.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{nc=Rt;var t=new nc;return t._=n,r(t)}finally{nc=Date}}var r=t(n);return e.parse=function(n){try{nc=Rt;var t=r.parse(n);return t&&t._}finally{nc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=re;var x=Zo.map(),M=Ht(v),_=Ft(v),b=Ht(d),w=Ft(d),S=Ht(m),k=Ft(m),E=Ht(y),A=Ft(y);p.forEach(function(n,t){x.set(n.toLowerCase(),t)});var C={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return jt(n.getDate(),t,2)},e:function(n,t){return jt(n.getDate(),t,2)},H:function(n,t){return jt(n.getHours(),t,2)},I:function(n,t){return jt(n.getHours()%12||12,t,2)},j:function(n,t){return jt(1+Qa.dayOfYear(n),t,3)},L:function(n,t){return jt(n.getMilliseconds(),t,3)},m:function(n,t){return jt(n.getMonth()+1,t,2)},M:function(n,t){return jt(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return jt(n.getSeconds(),t,2)},U:function(n,t){return jt(Qa.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return jt(Qa.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return jt(n.getFullYear()%100,t,2)},Y:function(n,t){return jt(n.getFullYear()%1e4,t,4)},Z:te,"%":function(){return"%"}},N={a:r,A:u,b:i,B:o,c:a,d:Wt,e:Wt,H:Gt,I:Gt,j:Jt,L:ne,m:Bt,M:Kt,p:l,S:Qt,U:Yt,w:Ot,W:It,x:c,X:s,y:Vt,Y:Zt,Z:Xt,"%":ee};return t}function jt(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Ht(n){return new RegExp("^(?:"+n.map(Zo.requote).join("|")+")","i")}function Ft(n){for(var t=new o,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Ot(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Yt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e));return r?(n.U=+r[0],e+r[0].length):-1}function It(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e));return r?(n.W=+r[0],e+r[0].length):-1}function Zt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Vt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.y=$t(+r[0]),e+r[0].length):-1}function Xt(n,t,e){return/^[+-]\d{4}$/.test(t=t.substring(e,e+5))?(n.Z=-t,e+5):-1}function $t(n){return n+(n>68?1900:2e3)}function Bt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Wt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function Jt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function Gt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function Kt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function Qt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ne(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function te(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(ua(t)/60),u=ua(t)%60;return e+jt(r,"0",2)+jt(u,"0",2)}function ee(n,t,e){uc.lastIndex=0;var r=uc.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function re(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ue(){}function ie(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function oe(n,t){n&&cc.hasOwnProperty(n.type)&&cc[n.type](n,t)}function ae(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function ce(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)ae(n[e],t,1);t.polygonEnd()}function se(){function n(n,t){n*=Aa,t=t*Aa/2+ba/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),s=Math.sin(t),l=i*s,f=u*c+l*Math.cos(a),h=l*o*Math.sin(a);lc.add(Math.atan2(h,f)),r=n,u=c,i=s}var t,e,r,u,i;fc.point=function(o,a){fc.point=n,r=(t=o)*Aa,u=Math.cos(a=(e=a)*Aa/2+ba/4),i=Math.sin(a)},fc.lineEnd=function(){n(t,e)}}function le(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function fe(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function he(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function ge(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function pe(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function ve(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function de(n){return[Math.atan2(n[1],n[0]),G(n[2])]}function me(n,t){return ua(n[0]-t[0])<ka&&ua(n[1]-t[1])<ka}function ye(n,t){n*=Aa;var e=Math.cos(t*=Aa);xe(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function xe(n,t,e){++hc,pc+=(n-pc)/hc,vc+=(t-vc)/hc,dc+=(e-dc)/hc}function Me(){function n(n,u){n*=Aa;var i=Math.cos(u*=Aa),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),s=Math.atan2(Math.sqrt((s=e*c-r*a)*s+(s=r*o-t*c)*s+(s=t*a-e*o)*s),t*o+e*a+r*c);gc+=s,mc+=s*(t+(t=o)),yc+=s*(e+(e=a)),xc+=s*(r+(r=c)),xe(t,e,r)}var t,e,r;wc.point=function(u,i){u*=Aa;var o=Math.cos(i*=Aa);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),wc.point=n,xe(t,e,r)}}function _e(){wc.point=ye}function be(){function n(n,t){n*=Aa;var e=Math.cos(t*=Aa),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),s=u*c-i*a,l=i*o-r*c,f=r*a-u*o,h=Math.sqrt(s*s+l*l+f*f),g=r*o+u*a+i*c,p=h&&-J(g)/h,v=Math.atan2(h,g);Mc+=p*s,_c+=p*l,bc+=p*f,gc+=v,mc+=v*(r+(r=o)),yc+=v*(u+(u=a)),xc+=v*(i+(i=c)),xe(r,u,i)}var t,e,r,u,i;wc.point=function(o,a){t=o,e=a,wc.point=n,o*=Aa;var c=Math.cos(a*=Aa);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),xe(r,u,i)},wc.lineEnd=function(){n(t,e),wc.lineEnd=_e,wc.point=ye}}function we(){return!0}function Se(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(me(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return u.lineEnd(),void 0}var c=new Ee(e,n,null,!0),s=new Ee(e,null,c,!1);c.o=s,i.push(c),o.push(s),c=new Ee(r,n,null,!1),s=new Ee(r,null,c,!0),c.o=s,i.push(c),o.push(s)}}),o.sort(t),ke(i),ke(o),i.length){for(var a=0,c=e,s=o.length;s>a;++a)o[a].e=c=!c;for(var l,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;l=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,s=l.length;s>a;++a)u.point((f=l[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){l=g.p.z;for(var a=l.length-1;a>=0;--a)u.point((f=l[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,l=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ke(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function Ee(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Ae(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function s(){y.point=o,d.lineEnd()}function l(n,t){v.push([n,t]);var e=u(n,t);M.point(e[0],e[1])}function f(){M.lineStart(),v=[]}function h(){l(v[0][0],v[0][1]),M.lineEnd();var n,t=M.clean(),e=x.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(_||(i.polygonStart(),_=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Ce))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:s,polygonStart:function(){y.point=l,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=s,g=Zo.merge(g);var n=Le(m,p);g.length?(_||(i.polygonStart(),_=!0),Se(g,ze,n,e,i)):n&&(_||(i.polygonStart(),_=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),_&&(i.polygonEnd(),_=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},x=Ne(),M=t(x),_=!1;return y}}function Ce(n){return n.length>1}function Ne(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:v,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function ze(n,t){return((n=n.x)[0]<0?n[1]-Sa-ka:Sa-n[1])-((t=t.x)[0]<0?t[1]-Sa-ka:Sa-t[1])}function Le(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;lc.reset();for(var a=0,c=t.length;c>a;++a){var s=t[a],l=s.length;if(l)for(var f=s[0],h=f[0],g=f[1]/2+ba/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===l&&(d=0),n=s[d];var m=n[0],y=n[1]/2+ba/4,x=Math.sin(y),M=Math.cos(y),_=m-h,b=_>=0?1:-1,w=b*_,S=w>ba,k=p*x;if(lc.add(Math.atan2(k*b*Math.sin(w),v*M+k*Math.cos(w))),i+=S?_+b*wa:_,S^h>=e^m>=e){var E=he(le(f),le(n));ve(E);var A=he(u,E);ve(A);var C=(S^_>=0?-1:1)*G(A[2]);(r>C||r===C&&(E[0]||E[1]))&&(o+=S^_>=0?1:-1)}if(!d++)break;h=m,p=x,v=M,f=n}}return(-ka>i||ka>i&&0>lc)^1&o}function Te(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?ba:-ba,c=ua(i-e);ua(c-ba)<ka?(n.point(e,r=(r+o)/2>0?Sa:-Sa),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=ba&&(ua(e-u)<ka&&(e-=u*ka),ua(i-a)<ka&&(i-=a*ka),r=qe(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function qe(n,t,e,r){var u,i,o=Math.sin(n-e);return ua(o)>ka?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function Re(n,t,e,r){var u;if(null==n)u=e*Sa,r.point(-ba,u),r.point(0,u),r.point(ba,u),r.point(ba,0),r.point(ba,-u),r.point(0,-u),r.point(-ba,-u),r.point(-ba,0),r.point(-ba,u);else if(ua(n[0]-t[0])>ka){var i=n[0]<t[0]?ba:-ba;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function De(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,s,l;return{lineStart:function(){s=c=!1,l=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?ba:-ba),h):0;if(!e&&(s=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(me(e,g)||me(p,g))&&(p[0]+=ka,p[1]+=ka,v=t(p[0],p[1]))),v!==c)l=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(l=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&me(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return l|(s&&c)<<1}}}function r(n,t,e){var r=le(n),u=le(t),o=[1,0,0],a=he(r,u),c=fe(a,a),s=a[0],l=c-s*s;if(!l)return!e&&n;var f=i*c/l,h=-i*s/l,g=he(o,a),p=pe(o,f),v=pe(a,h);ge(p,v);var d=g,m=fe(p,d),y=fe(d,d),x=m*m-y*(fe(p,p)-1);if(!(0>x)){var M=Math.sqrt(x),_=pe(d,(-m-M)/y);if(ge(_,p),_=de(_),!e)return _;var b,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(b=w,w=S,S=b);var A=S-w,C=ua(A-ba)<ka,N=C||ka>A;if(!C&&k>E&&(b=k,k=E,E=b),N?C?k+E>0^_[1]<(ua(_[0]-w)<ka?k:E):k<=_[1]&&_[1]<=E:A>ba^(w<=_[0]&&_[0]<=S)){var z=pe(d,(-m+M)/y);return ge(z,p),[_,de(z)]}}}function u(t,e){var r=o?n:ba-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ua(i)>ka,c=sr(n,6*Aa);return Ae(t,e,c,o?[0,-n]:[-ba,n-ba])}function Pe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,s=o.y,l=a.x,f=a.y,h=0,g=1,p=l-c,v=f-s;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-s,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-s,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:s+h*v}),1>g&&(u.b={x:c+g*p,y:s+g*v}),u}}}}}}function Ue(n,t,e,r){function u(r,u){return ua(r[0]-n)<ka?u>0?0:3:ua(r[0]-e)<ka?u>0?2:1:ua(r[1]-t)<ka?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,s=a[0];c>o;++o)i=a[o],s[1]<=r?i[1]>r&&W(s,i,n)>0&&++t:i[1]<=r&&W(s,i,n)<0&&--t,s=i;return 0!==t}function s(i,a,c,s){var l=0,f=0;if(null==i||(l=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do s.point(0===l||3===l?n:e,l>1?r:t);while((l=(l+c+4)%4)!==f)}else s.point(a[0],a[1])}function l(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){l(n,t)&&a.point(n,t)}function h(){N.point=p,d&&d.push(m=[]),S=!0,w=!1,_=b=0/0}function g(){v&&(p(y,x),M&&w&&A.rejoin(),v.push(A.buffer())),N.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-kc,Math.min(kc,n)),t=Math.max(-kc,Math.min(kc,t));var e=l(n,t);if(d&&m.push([n,t]),S)y=n,x=t,M=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:_,y:b},b:{x:n,y:t}};C(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}_=n,b=t,w=e}var v,d,m,y,x,M,_,b,w,S,k,E=a,A=Ne(),C=Pe(n,t,e,r),N={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=Zo.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),s(null,null,1,a),a.lineEnd()),u&&Se(v,i,t,s,a),a.polygonEnd()),v=d=m=null}};return N}}function je(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function He(n){var t=0,e=ba/3,r=tr(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*ba/180,e=n[1]*ba/180):[180*(t/ba),180*(e/ba)]},u}function Fe(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,G((i-(n*n+e*e)*u*u)/(2*u))]},e}function Oe(){function n(n,t){Ac+=u*n-r*t,r=n,u=t}var t,e,r,u;Tc.point=function(i,o){Tc.point=n,t=r=i,e=u=o},Tc.lineEnd=function(){n(t,e)}}function Ye(n,t){Cc>n&&(Cc=n),n>zc&&(zc=n),Nc>t&&(Nc=t),t>Lc&&(Lc=t)}function Ie(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Ze(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Ze(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Ze(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Ve(n,t){pc+=n,vc+=t,++dc}function Xe(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);mc+=o*(t+n)/2,yc+=o*(e+r)/2,xc+=o,Ve(t=n,e=r)}var t,e;Rc.point=function(r,u){Rc.point=n,Ve(t=r,e=u)}}function $e(){Rc.point=Ve}function Be(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);mc+=o*(r+n)/2,yc+=o*(u+t)/2,xc+=o,o=u*n-r*t,Mc+=o*(r+n),_c+=o*(u+t),bc+=3*o,Ve(r=n,u=t)}var t,e,r,u;Rc.point=function(i,o){Rc.point=n,Ve(t=r=i,e=u=o)},Rc.lineEnd=function(){n(t,e)}}function We(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,wa)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:v};return a}function Je(n){function t(n){return(a?r:e)(n)}function e(t){return Qe(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){x=0/0,S.point=i,t.lineStart()}function i(e,r){var i=le([e,r]),o=n(e,r);u(x,M,y,_,b,w,x=o[0],M=o[1],y=e,_=i[0],b=i[1],w=i[2],a,t),t.point(x,M)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=s,S.lineEnd=l}function s(n,t){i(f=n,h=t),g=x,p=M,v=_,d=b,m=w,S.point=i}function l(){u(x,M,y,_,b,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,x,M,_,b,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,s,l,f,h,g,p,v,d,m){var y=l-t,x=f-e,M=y*y+x*x;if(M>4*i&&d--){var _=a+g,b=c+p,w=s+v,S=Math.sqrt(_*_+b*b+w*w),k=Math.asin(w/=S),E=ua(ua(w)-1)<ka||ua(r-h)<ka?(r+h)/2:Math.atan2(b,_),A=n(E,k),C=A[0],N=A[1],z=C-t,L=N-e,T=x*z-y*L;(T*T/M>i||ua((y*z+x*L)/M-.5)>.3||o>a*g+c*p+s*v)&&(u(t,e,r,a,c,s,C,N,E,_/=S,b/=S,w,d,m),m.point(C,N),u(C,N,E,_,b,w,l,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Aa),a=16; - return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function Ge(n){var t=Je(function(t,e){return n([t*Ca,e*Ca])});return function(n){return er(t(n))}}function Ke(n){this.stream=n}function Qe(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function nr(n){return tr(function(){return n})()}function tr(n){function t(n){return n=a(n[0]*Aa,n[1]*Aa),[n[0]*h+c,s-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(s-n[1])/h),n&&[n[0]*Ca,n[1]*Ca]}function r(){a=je(o=ir(m,y,x),i);var n=i(v,d);return c=g-n[0]*h,s=p+n[1]*h,u()}function u(){return l&&(l.valid=!1,l=null),t}var i,o,a,c,s,l,f=Je(function(n,t){return n=i(n,t),[n[0]*h+c,s-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,y=0,x=0,M=Sc,_=wt,b=null,w=null;return t.stream=function(n){return l&&(l.valid=!1),l=er(M(o,f(_(n)))),l.valid=!0,l},t.clipAngle=function(n){return arguments.length?(M=null==n?(b=n,Sc):De((b=+n)*Aa),u()):b},t.clipExtent=function(n){return arguments.length?(w=n,_=n?Ue(n[0][0],n[0][1],n[1][0],n[1][1]):wt,u()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Aa,d=n[1]%360*Aa,r()):[v*Ca,d*Ca]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Aa,y=n[1]%360*Aa,x=n.length>2?n[2]%360*Aa:0,r()):[m*Ca,y*Ca,x*Ca]},Zo.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function er(n){return Qe(n,function(t,e){n.point(t*Aa,e*Aa)})}function rr(n,t){return[n,t]}function ur(n,t){return[n>ba?n-wa:-ba>n?n+wa:n,t]}function ir(n,t,e){return n?t||e?je(ar(n),cr(t,e)):ar(n):t||e?cr(t,e):ur}function or(n){return function(t,e){return t+=n,[t>ba?t-wa:-ba>t?t+wa:t,e]}}function ar(n){var t=or(n);return t.invert=or(-n),t}function cr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*r+a*u;return[Math.atan2(c*i-l*o,a*r-s*u),G(l*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*i-c*o;return[Math.atan2(c*i+s*o,a*r+l*u),G(l*r-a*u)]},e}function sr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=lr(e,u),i=lr(e,i),(o>0?i>u:u>i)&&(u+=o*wa)):(u=n+o*wa,i=n-.5*c);for(var s,l=u;o>0?l>i:i>l;l-=c)a.point((s=de([e,-r*Math.cos(l),-r*Math.sin(l)]))[0],s[1])}}function lr(n,t){var e=le(t);e[0]-=n,ve(e);var r=J(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-ka)%(2*Math.PI)}function fr(n,t,e){var r=Zo.range(n,t-ka,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function hr(n,t,e){var r=Zo.range(n,t-ka,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function gr(n){return n.source}function pr(n){return n.target}function vr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),s=u*Math.sin(n),l=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(tt(r-t)+u*o*tt(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*l,u=e*s+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Ca,Math.atan2(o,Math.sqrt(r*r+u*u))*Ca]}:function(){return[n*Ca,t*Ca]};return p.distance=h,p}function dr(){function n(n,u){var i=Math.sin(u*=Aa),o=Math.cos(u),a=ua((n*=Aa)-t),c=Math.cos(a);Dc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Pc.point=function(u,i){t=u*Aa,e=Math.sin(i*=Aa),r=Math.cos(i),Pc.point=n},Pc.lineEnd=function(){Pc.point=Pc.lineEnd=v}}function mr(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function yr(n,t){function e(n,t){o>0?-Sa+ka>t&&(t=-Sa+ka):t>Sa-ka&&(t=Sa-ka);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(ba/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=B(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Sa]},e):Mr}function xr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ua(u)<ka?rr:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-B(u)*Math.sqrt(n*n+e*e)]},e)}function Mr(n,t){return[n,Math.log(Math.tan(ba/4+t/2))]}function _r(n){var t,e=nr(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=ba*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function br(n,t){return[Math.log(Math.tan(ba/4+t/2)),-n]}function wr(n){return n[0]}function Sr(n){return n[1]}function kr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&W(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function Er(n,t){return n[0]-t[0]||n[1]-t[1]}function Ar(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Cr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],s=e[1],l=t[1]-c,f=r[1]-s,h=(a*(c-s)-f*(u-i))/(f*o-a*l);return[u+h*o,c+h*l]}function Nr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function zr(){Gr(this),this.edge=this.site=this.circle=null}function Lr(n){var t=Bc.pop()||new zr;return t.site=n,t}function Tr(n){Yr(n),Vc.remove(n),Bc.push(n),Gr(n)}function qr(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Tr(n);for(var c=i;c.circle&&ua(e-c.circle.x)<ka&&ua(r-c.circle.cy)<ka;)i=c.P,a.unshift(c),Tr(c),c=i;a.unshift(c),Yr(c);for(var s=o;s.circle&&ua(e-s.circle.x)<ka&&ua(r-s.circle.cy)<ka;)o=s.N,a.push(s),Tr(s),s=o;a.push(s),Yr(s);var l,f=a.length;for(l=1;f>l;++l)s=a[l],c=a[l-1],Br(s.edge,c.site,s.site,u);c=a[0],s=a[f-1],s.edge=Xr(c.site,s.site,null,u),Or(c),Or(s)}function Rr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Vc._;a;)if(r=Dr(a,o)-i,r>ka)a=a.L;else{if(u=i-Pr(a,o),!(u>ka)){r>-ka?(t=a.P,e=a):u>-ka?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Lr(n);if(Vc.insert(t,c),t||e){if(t===e)return Yr(t),e=Lr(t.site),Vc.insert(c,e),c.edge=e.edge=Xr(t.site,c.site),Or(t),Or(e),void 0;if(!e)return c.edge=Xr(t.site,c.site),void 0;Yr(t),Yr(e);var s=t.site,l=s.x,f=s.y,h=n.x-l,g=n.y-f,p=e.site,v=p.x-l,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,x=v*v+d*d,M={x:(d*y-g*x)/m+l,y:(h*x-v*y)/m+f};Br(e.edge,s,p,M),c.edge=Xr(s,n,null,M),e.edge=Xr(n,p,null,M),Or(t),Or(e)}}function Dr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,s=c-t;if(!s)return a;var l=a-r,f=1/i-1/s,h=l/s;return f?(-h+Math.sqrt(h*h-2*f*(l*l/(-2*s)-c+s/2+u-i/2)))/f+r:(r+a)/2}function Pr(n,t){var e=n.N;if(e)return Dr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ur(n){this.site=n,this.edges=[]}function jr(n){for(var t,e,r,u,i,o,a,c,s,l,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Zc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)l=a[o].end(),r=l.x,u=l.y,s=a[++o%c].start(),t=s.x,e=s.y,(ua(r-t)>ka||ua(u-e)>ka)&&(a.splice(o,0,new Wr($r(i.site,l,ua(r-f)<ka&&p-u>ka?{x:f,y:ua(t-f)<ka?e:p}:ua(u-p)<ka&&h-r>ka?{x:ua(e-p)<ka?t:h,y:p}:ua(r-h)<ka&&u-g>ka?{x:h,y:ua(t-h)<ka?e:g}:ua(u-g)<ka&&r-f>ka?{x:ua(e-g)<ka?t:f,y:g}:null),i.site,null)),++c)}function Hr(n,t){return t.angle-n.angle}function Fr(){Gr(this),this.x=this.y=this.arc=this.site=this.cy=null}function Or(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,s=r.y-a,l=i.x-o,f=i.y-a,h=2*(c*f-s*l);if(!(h>=-Ea)){var g=c*c+s*s,p=l*l+f*f,v=(f*g-s*p)/h,d=(c*p-l*g)/h,f=d+a,m=Wc.pop()||new Fr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,x=$c._;x;)if(m.y<x.y||m.y===x.y&&m.x<=x.x){if(!x.L){y=x.P;break}x=x.L}else{if(!x.R){y=x;break}x=x.R}$c.insert(y,m),y||(Xc=m)}}}}function Yr(n){var t=n.circle;t&&(t.P||(Xc=t.N),$c.remove(t),Wc.push(t),Gr(t),n.circle=null)}function Ir(n){for(var t,e=Ic,r=Pe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Zr(t,n)||!r(t)||ua(t.a.x-t.b.x)<ka&&ua(t.a.y-t.b.y)<ka)&&(t.a=t.b=null,e.splice(u,1))}function Zr(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],s=t[1][1],l=n.l,f=n.r,h=l.x,g=l.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=s)return}else i={x:d,y:c};e={x:d,y:s}}else{if(i){if(i.y<c)return}else i={x:d,y:s};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=s)return}else i={x:(c-u)/r,y:c};e={x:(s-u)/r,y:s}}else{if(i){if(i.y<c)return}else i={x:(s-u)/r,y:s};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Vr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Xr(n,t,e,r){var u=new Vr(n,t);return Ic.push(u),e&&Br(u,n,t,e),r&&Br(u,t,n,r),Zc[n.i].edges.push(new Wr(u,n,t)),Zc[t.i].edges.push(new Wr(u,t,n)),u}function $r(n,t,e){var r=new Vr(n,null);return r.a=t,r.b=e,Ic.push(r),r}function Br(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Wr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function Jr(){this._=null}function Gr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function Kr(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Qr(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function nu(n){for(;n.L;)n=n.L;return n}function tu(n,t){var e,r,u,i=n.sort(eu).pop();for(Ic=[],Zc=new Array(n.length),Vc=new Jr,$c=new Jr;;)if(u=Xc,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Zc[i.i]=new Ur(i),Rr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;qr(u.arc)}t&&(Ir(t),jr(t));var o={cells:Zc,edges:Ic};return Vc=$c=Ic=Zc=null,o}function eu(n,t){return t.y-n.y||t.x-n.x}function ru(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function uu(n){return n.x}function iu(n){return n.y}function ou(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function au(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&au(n,c[0],e,r,o,a),c[1]&&au(n,c[1],o,r,u,a),c[2]&&au(n,c[2],e,a,o,i),c[3]&&au(n,c[3],o,a,u,i)}}function cu(n,t){n=Zo.rgb(n),t=Zo.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+dt(Math.round(e+i*n))+dt(Math.round(r+o*n))+dt(Math.round(u+a*n))}}function su(n,t){var e,r={},u={};for(e in n)e in t?r[e]=hu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function lu(n,t){return t-=n=+n,function(e){return n+t*e}}function fu(n,t){var e,r,u,i=Gc.lastIndex=Kc.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=Gc.exec(n))&&(r=Kc.exec(t));)(u=r.index)>i&&(u=t.substring(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:lu(e,r)})),i=Kc.lastIndex;return i<t.length&&(u=t.substring(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function hu(n,t){for(var e,r=Zo.interpolators.length;--r>=0&&!(e=Zo.interpolators[r](n,t)););return e}function gu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(hu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function pu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function vu(n){return function(t){return 1-n(1-t)}}function du(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function mu(n){return n*n}function yu(n){return n*n*n}function xu(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Mu(n){return function(t){return Math.pow(t,n)}}function _u(n){return 1-Math.cos(n*Sa)}function bu(n){return Math.pow(2,10*(n-1))}function wu(n){return 1-Math.sqrt(1-n*n)}function Su(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/wa*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*wa/t)}}function ku(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Eu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Au(n,t){n=Zo.hcl(n),t=Zo.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ot(e+i*n,r+o*n,u+a*n)+""}}function Cu(n,t){n=Zo.hsl(n),t=Zo.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ut(e+i*n,r+o*n,u+a*n)+""}}function Nu(n,t){n=Zo.lab(n),t=Zo.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function zu(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Lu(n){var t=[n.a,n.b],e=[n.c,n.d],r=qu(t),u=Tu(t,e),i=qu(Ru(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Ca,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Ca:0}function Tu(n,t){return n[0]*t[0]+n[1]*t[1]}function qu(n){var t=Math.sqrt(Tu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Ru(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Du(n,t){var e,r=[],u=[],i=Zo.transform(n),o=Zo.transform(t),a=i.translate,c=o.translate,s=i.rotate,l=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:lu(a[0],c[0])},{i:3,x:lu(a[1],c[1])})):c[0]||c[1]?r.push("translate("+c+")"):r.push(""),s!=l?(s-l>180?l+=360:l-s>180&&(s+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:lu(s,l)})):l&&r.push(r.pop()+"rotate("+l+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:lu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:lu(g[0],p[0])},{i:e-2,x:lu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Pu(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return(e-n)*t}}function Uu(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return Math.max(0,Math.min(1,(e-n)*t))}}function ju(n){for(var t=n.source,e=n.target,r=Fu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Hu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Fu(n,t){if(n===t)return n;for(var e=Hu(n),r=Hu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Ou(n){n.fixed|=2}function Yu(n){n.fixed&=-7}function Iu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Zu(n){n.fixed&=-5}function Vu(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Vu(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var s=t*e[n.point.index];n.charge+=n.pointCharge=s,r+=s*n.point.x,u+=s*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Xu(n,t){return Zo.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=Ku,n}function $u(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Bu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function Wu(n){return n.children}function Ju(n){return n.value}function Gu(n,t){return t.value-n.value}function Ku(n){return Zo.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function Qu(n){return n.x}function ni(n){return n.y}function ti(n,t,e){n.y0=t,n.y=e}function ei(n){return Zo.range(n.length)}function ri(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function ui(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function ii(n){return n.reduce(oi,0)}function oi(n,t){return n+t[1]}function ai(n,t){return ci(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function ci(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function si(n){return[Zo.min(n),Zo.max(n)]}function li(n,t){return n.value-t.value}function fi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function hi(n,t){n._pack_next=t,t._pack_prev=n}function gi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function pi(n){function t(n){l=Math.min(n.x-n.r,l),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(s=e.length)){var e,r,u,i,o,a,c,s,l=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(vi),r=e[0],r.x=-r.r,r.y=0,t(r),s>1&&(u=e[1],u.x=u.r,u.y=0,t(u),s>2))for(i=e[2],yi(r,u,i),t(i),fi(r,i),r._pack_prev=i,fi(i,u),u=r._pack_next,o=3;s>o;o++){yi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(gi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!gi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?hi(r,u=a):hi(r=c,u),o--):(fi(r,i),u=i,t(i))}var m=(l+f)/2,y=(h+g)/2,x=0;for(o=0;s>o;o++)i=e[o],i.x-=m,i.y-=y,x=Math.max(x,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=x,e.forEach(di)}}function vi(n){n._pack_next=n._pack_prev=n}function di(n){delete n._pack_next,delete n._pack_prev}function mi(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)mi(u[i],t,e,r)}function yi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),s=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+s*i,e.y=n.y+c*i-s*u}else e.x=n.x+r,e.y=n.y}function xi(n,t){return n.parent==t.parent?1:2}function Mi(n){var t=n.children;return t.length?t[0]:n.t}function _i(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function bi(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function wi(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Si(n,t,e){return n.a.parent===t.parent?n.a:e}function ki(n){return 1+Zo.max(n,function(n){return n.y})}function Ei(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Ai(n){var t=n.children;return t&&t.length?Ai(t[0]):n}function Ci(n){var t,e=n.children;return e&&(t=e.length)?Ci(e[t-1]):n}function Ni(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function zi(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Li(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ti(n){return n.rangeExtent?n.rangeExtent():Li(n.range())}function qi(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Ri(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Di(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ss}function Pi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=Zo.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ui(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Pi:qi,c=r?Uu:Pu;return o=u(n,t,c,e),a=u(t,n,c,hu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(zu)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Oi(n,t)},i.tickFormat=function(t,e){return Yi(n,t,e)},i.nice=function(t){return Hi(n,t),u()},i.copy=function(){return Ui(n,t,e,r)},u()}function ji(n,t){return Zo.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Hi(n,t){return Ri(n,Di(Fi(n,t)[2]))}function Fi(n,t){null==t&&(t=10);var e=Li(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Oi(n,t){return Zo.range.apply(Zo,Fi(n,t))}function Yi(n,t,e){var r=Fi(n,t);if(e){var u=Ga.exec(e);if(u.shift(),"s"===u[8]){var i=Zo.formatPrefix(Math.max(ua(r[0]),ua(r[1])));return u[7]||(u[7]="."+Ii(i.scale(r[2]))),u[8]="f",e=Zo.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Zi(u[8],r)),e=u.join("")}else e=",."+Ii(r[2])+"f";return Zo.format(e)}function Ii(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Zi(n,t){var e=Ii(t[2]);return n in ls?Math.abs(e-Ii(Math.max(ua(t[0]),ua(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Vi(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Ri(r.map(u),e?Math:hs);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Li(r),o=[],a=n[0],c=n[1],s=Math.floor(u(a)),l=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(l-s)){if(e){for(;l>s;s++)for(var h=1;f>h;h++)o.push(i(s)*h);o.push(i(s))}else for(o.push(i(s));s++<l;)for(var h=f-1;h>0;h--)o.push(i(s)*h);for(s=0;o[s]<a;s++);for(l=o.length;o[l-1]>c;l--);o=o.slice(s,l)}return o},o.tickFormat=function(n,t){if(!arguments.length)return fs;arguments.length<2?t=fs:"function"!=typeof t&&(t=Zo.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Vi(n.copy(),t,e,r)},ji(o,n)}function Xi(n,t,e){function r(t){return n(u(t))}var u=$i(t),i=$i(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Oi(e,n)},r.tickFormat=function(n,t){return Yi(e,n,t)},r.nice=function(n){return r.domain(Hi(e,n))},r.exponent=function(o){return arguments.length?(u=$i(t=o),i=$i(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Xi(n.copy(),t,e)},ji(r,n)}function $i(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Bi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return Zo.range(n.length).map(function(n){return t+e*n})}var u,i,a;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new o;for(var i,a=-1,c=r.length;++a<c;)u.has(i=r[a])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,a=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,o){arguments.length<2&&(o=0);var c=u[0],s=u[1],l=(s-c)/(Math.max(1,n.length-1)+o);return i=r(n.length<2?(c+s)/2:c+l*o/2,l),a=0,t={t:"rangePoints",a:arguments},e},e.rangeBands=function(u,o,c){arguments.length<2&&(o=0),arguments.length<3&&(c=o);var s=u[1]<u[0],l=u[s-0],f=u[1-s],h=(f-l)/(n.length-o+2*c);return i=r(l+h*c,h),s&&i.reverse(),a=h*(1-o),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,o,c){arguments.length<2&&(o=0),arguments.length<3&&(c=o);var s=u[1]<u[0],l=u[s-0],f=u[1-s],h=Math.floor((f-l)/(n.length-o+2*c)),g=f-l-(n.length-o)*h;return i=r(l+Math.round(g/2),h),s&&i.reverse(),a=Math.round(h*(1-o)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return a},e.rangeExtent=function(){return Li(t.a[0])},e.copy=function(){return Bi(n,t)},e.domain(n)}function Wi(e,r){function u(){var n=0,t=r.length;for(o=[];++n<t;)o[n-1]=Zo.quantile(e,n/t);return i}function i(n){return isNaN(n=+n)?void 0:r[Zo.bisect(o,n)]}var o;return i.domain=function(r){return arguments.length?(e=r.filter(t).sort(n),u()):e},i.range=function(n){return arguments.length?(r=n,u()):r},i.quantiles=function(){return o},i.invertExtent=function(n){return n=r.indexOf(n),0>n?[0/0,0/0]:[n>0?o[n-1]:e[0],n<o.length?o[n]:e[e.length-1]]},i.copy=function(){return Wi(e,r)},u()}function Ji(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return Ji(n,t,e)},u()}function Gi(n,t){function e(e){return e>=e?t[Zo.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return Gi(n,t)},e}function Ki(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Oi(n,t)},t.tickFormat=function(t,e){return Yi(n,t,e)},t.copy=function(){return Ki(n)},t}function Qi(n){return n.innerRadius}function no(n){return n.outerRadius}function to(n){return n.startAngle}function eo(n){return n.endAngle}function ro(n){function t(t){function o(){s.push("M",i(n(l),a))}for(var c,s=[],l=[],f=-1,h=t.length,g=bt(e),p=bt(r);++f<h;)u.call(this,c=t[f],f)?l.push([+g.call(this,c,f),+p.call(this,c,f)]):l.length&&(o(),l=[]);return l.length&&o(),s.length?s.join(""):null}var e=wr,r=Sr,u=we,i=uo,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=xs.get(n)||uo).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function uo(n){return n.join("L")}function io(n){return uo(n)+"Z"}function oo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function ao(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function co(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function so(n,t){return n.length<4?uo(n):n[1]+ho(n.slice(1,n.length-1),go(n,t))}function lo(n,t){return n.length<3?uo(n):n[0]+ho((n.push(n[0]),n),go([n[n.length-2]].concat(n,[n[1]]),t))}function fo(n,t){return n.length<3?uo(n):n[0]+ho(n,go(n,t))}function ho(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return uo(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var s=2;s<t.length;s++,c++)i=n[c],a=t[s],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var l=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+l[0]+","+l[1]}return r}function go(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function po(n){if(n.length<3)return uo(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",xo(bs,o),",",xo(bs,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Mo(c,o,a);return n.pop(),c.push("L",r),c.join("")}function vo(n){if(n.length<4)return uo(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(xo(bs,i)+","+xo(bs,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Mo(e,i,o);return e.join("")}function mo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[xo(bs,o),",",xo(bs,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Mo(t,o,a);return t.join("")}function yo(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,s=-1;++s<=e;)r=n[s],u=s/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return po(n)}function xo(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Mo(n,t,e){n.push("C",xo(Ms,t),",",xo(Ms,e),",",xo(_s,t),",",xo(_s,e),",",xo(bs,t),",",xo(bs,e))}function _o(n,t){return(t[1]-n[1])/(t[0]-n[0])}function bo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=_o(u,i);++t<e;)r[t]=(o+(o=_o(u=i,i=n[t+1])))/2;return r[t]=o,r}function wo(n){for(var t,e,r,u,i=[],o=bo(n),a=-1,c=n.length-1;++a<c;)t=_o(n[a],n[a+1]),ua(t)<ka?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function So(n){return n.length<3?uo(n):n[0]+ho(n,wo(n))}function ko(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]+ms,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Eo(n){function t(t){function c(){v.push("M",a(n(m),f),l,s(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,x=t.length,M=bt(e),_=bt(u),b=e===r?function(){return g}:bt(r),w=u===i?function(){return p}:bt(i);++y<x;)o.call(this,h=t[y],y)?(d.push([g=+M.call(this,h,y),p=+_.call(this,h,y)]),m.push([+b.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=wr,r=wr,u=0,i=Sr,o=we,a=uo,c=a.key,s=a,l="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=xs.get(n)||uo).key,s=a.reverse||a,l=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Ao(n){return n.radius}function Co(n){return[n.x,n.y]}function No(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]+ms;return[e*Math.cos(r),e*Math.sin(r)]}}function zo(){return 64}function Lo(){return"circle"}function To(n){var t=Math.sqrt(n/ba);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function qo(n,t){return sa(n,Cs),n.id=t,n}function Ro(n,t,e,r){var u=n.id;return P(n,"function"==typeof e?function(n,i,o){n.__transition__[u].tween.set(t,r(e.call(n,n.__data__,i,o)))}:(e=r(e),function(n){n.__transition__[u].tween.set(t,e)}))}function Do(n){return null==n&&(n=""),function(){this.textContent=n}}function Po(n,t,e,r){var u=n.__transition__||(n.__transition__={active:0,count:0}),i=u[e];if(!i){var a=r.time;i=u[e]={tween:new o,time:a,ease:r.ease,delay:r.delay,duration:r.duration},++u.count,Zo.timer(function(r){function o(r){return u.active>e?s():(u.active=e,i.event&&i.event.start.call(n,l,t),i.tween.forEach(function(e,r){(r=r.call(n,l,t))&&v.push(r)}),Zo.timer(function(){return p.c=c(r||1)?we:c,1},0,a),void 0)}function c(r){if(u.active!==e)return s();for(var o=r/g,a=f(o),c=v.length;c>0;)v[--c].call(n,a); - return o>=1?(i.event&&i.event.end.call(n,l,t),s()):void 0}function s(){return--u.count?delete u[e]:delete n.__transition__,1}var l=n.__data__,f=i.ease,h=i.delay,g=i.duration,p=Ba,v=[];return p.t=h+a,r>=h?o(r-h):(p.c=o,void 0)},0,a)}}function Uo(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}function jo(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function Ho(n){return n.toISOString()}function Fo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=Zo.bisect(Us,u);return i==Us.length?[t.year,Fi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Us[i-1]<Us[i]/u?i-1:i]:[Fs,Fi(n,e)[2]]}return r.invert=function(t){return Oo(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Oo)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Oo(+e+1),t).length}var i=r.domain(),o=Li(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Ri(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Oo(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Oo(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Li(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Oo(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Fo(n.copy(),t,e)},ji(r,n)}function Oo(n){return new Date(n)}function Yo(n){return JSON.parse(n.responseText)}function Io(n){var t=$o.createRange();return t.selectNode($o.body),t.createContextualFragment(n.responseText)}var Zo={version:"3.4.11"};Date.now||(Date.now=function(){return+new Date});var Vo=[].slice,Xo=function(n){return Vo.call(n)},$o=document,Bo=$o.documentElement,Wo=window;try{Xo(Bo.childNodes)[0].nodeType}catch(Jo){Xo=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}try{$o.createElement("div").style.setProperty("opacity",0,"")}catch(Go){var Ko=Wo.Element.prototype,Qo=Ko.setAttribute,na=Ko.setAttributeNS,ta=Wo.CSSStyleDeclaration.prototype,ea=ta.setProperty;Ko.setAttribute=function(n,t){Qo.call(this,n,t+"")},Ko.setAttributeNS=function(n,t,e){na.call(this,n,t,e+"")},ta.setProperty=function(n,t,e){ea.call(this,n,t+"",e)}}Zo.ascending=n,Zo.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},Zo.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},Zo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},Zo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o&&!(null!=(e=u=n[i])&&e>=e);)e=u=void 0;for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o&&!(null!=(e=u=t.call(n,n[i],i))&&e>=e);)e=void 0;for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},Zo.sum=function(n,t){var e,r=0,u=n.length,i=-1;if(1===arguments.length)for(;++i<u;)isNaN(e=+n[i])||(r+=e);else for(;++i<u;)isNaN(e=+t.call(n,n[i],i))||(r+=e);return r},Zo.mean=function(n,e){var r,u=0,i=n.length,o=-1,a=i;if(1===arguments.length)for(;++o<i;)t(r=n[o])?u+=r:--a;else for(;++o<i;)t(r=e.call(n,n[o],o))?u+=r:--a;return a?u/a:void 0},Zo.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},Zo.median=function(e,r){return arguments.length>1&&(e=e.map(r)),e=e.filter(t),e.length?Zo.quantile(e.sort(n),.5):void 0};var ra=e(n);Zo.bisectLeft=ra.left,Zo.bisect=Zo.bisectRight=ra.right,Zo.bisector=function(t){return e(1===t.length?function(e,r){return n(t(e),r)}:t)},Zo.shuffle=function(n){for(var t,e,r=n.length;r;)e=0|Math.random()*r--,t=n[r],n[r]=n[e],n[e]=t;return n},Zo.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},Zo.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},Zo.zip=function(){if(!(u=arguments.length))return[];for(var n=-1,t=Zo.min(arguments,r),e=new Array(t);++n<t;)for(var u,i=-1,o=e[n]=new Array(u);++i<u;)o[i]=arguments[i][n];return e},Zo.transpose=function(n){return Zo.zip.apply(Zo,n)},Zo.keys=function(n){var t=[];for(var e in n)t.push(e);return t},Zo.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},Zo.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},Zo.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ua=Math.abs;Zo.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/e)throw new Error("infinite range");var r,i=[],o=u(ua(e)),a=-1;if(n*=o,t*=o,e*=o,0>e)for(;(r=n+e*++a)>t;)i.push(r/o);else for(;(r=n+e*++a)<t;)i.push(r/o);return i},Zo.map=function(n){var t=new o;if(n instanceof o)n.forEach(function(n,e){t.set(n,e)});else for(var e in n)t.set(e,n[e]);return t},i(o,{has:a,get:function(n){return this[ia+n]},set:function(n,t){return this[ia+n]=t},remove:c,keys:s,values:function(){var n=[];return this.forEach(function(t,e){n.push(e)}),n},entries:function(){var n=[];return this.forEach(function(t,e){n.push({key:t,value:e})}),n},size:l,empty:f,forEach:function(n){for(var t in this)t.charCodeAt(0)===oa&&n.call(this,t.substring(1),this[t])}});var ia="\x00",oa=ia.charCodeAt(0);Zo.nest=function(){function n(t,a,c){if(c>=i.length)return r?r.call(u,a):e?a.sort(e):a;for(var s,l,f,h,g=-1,p=a.length,v=i[c++],d=new o;++g<p;)(h=d.get(s=v(l=a[g])))?h.push(l):d.set(s,[l]);return t?(l=t(),f=function(e,r){l.set(e,n(t,r,c))}):(l={},f=function(e,r){l[e]=n(t,r,c)}),d.forEach(f),l}function t(n,e){if(e>=i.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],a=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(Zo.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return a[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},Zo.set=function(n){var t=new h;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},i(h,{has:a,add:function(n){return this[ia+n]=!0,n},remove:function(n){return n=ia+n,n in this&&delete this[n]},values:s,size:l,empty:f,forEach:function(n){for(var t in this)t.charCodeAt(0)===oa&&n.call(this,t.substring(1))}}),Zo.behavior={},Zo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=g(n,t,t[e]);return n};var aa=["webkit","ms","moz","Moz","o","O"];Zo.dispatch=function(){for(var n=new d,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=m(n);return n},d.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},Zo.event=null,Zo.requote=function(n){return n.replace(ca,"\\$&")};var ca=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,sa={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},la=function(n,t){return t.querySelector(n)},fa=function(n,t){return t.querySelectorAll(n)},ha=Bo.matches||Bo[p(Bo,"matchesSelector")],ga=function(n,t){return ha.call(n,t)};"function"==typeof Sizzle&&(la=function(n,t){return Sizzle(n,t)[0]||null},fa=Sizzle,ga=Sizzle.matchesSelector),Zo.selection=function(){return ma};var pa=Zo.selection.prototype=[];pa.select=function(n){var t,e,r,u,i=[];n=b(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,s=r.length;++c<s;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return _(i)},pa.selectAll=function(n){var t,e,r=[];n=w(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=Xo(n.call(e,e.__data__,a,u))),t.parentNode=e);return _(r)};var va={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};Zo.ns={prefix:va,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.substring(0,t),n=n.substring(t+1)),va.hasOwnProperty(e)?{space:va[e],local:n}:n}},pa.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=Zo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(S(t,n[t]));return this}return this.each(S(n,t))},pa.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=A(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!E(n[u]).test(t))return!1;return!0}for(t in n)this.each(C(t,n[t]));return this}return this.each(C(n,t))},pa.style=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t="");for(e in n)this.each(z(e,n[e],t));return this}if(2>r)return Wo.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return this.each(z(n,t,e))},pa.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(L(t,n[t]));return this}return this.each(L(n,t))},pa.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},pa.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},pa.append=function(n){return n=T(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},pa.insert=function(n,t){return n=T(n),t=b(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},pa.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},pa.data=function(n,t){function e(n,e){var r,u,i,a=n.length,f=e.length,h=Math.min(a,f),g=new Array(f),p=new Array(f),v=new Array(a);if(t){var d,m=new o,y=new o,x=[];for(r=-1;++r<a;)d=t.call(u=n[r],u.__data__,r),m.has(d)?v[r]=u:m.set(d,u),x.push(d);for(r=-1;++r<f;)d=t.call(e,i=e[r],r),(u=m.get(d))?(g[r]=u,u.__data__=i):y.has(d)||(p[r]=q(i)),y.set(d,i),m.remove(d);for(r=-1;++r<a;)m.has(x[r])&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=q(i);for(;f>r;++r)p[r]=q(e[r]);for(;a>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,c.push(p),s.push(g),l.push(v)}var r,u,i=-1,a=this.length;if(!arguments.length){for(n=new Array(a=(r=this[0]).length);++i<a;)(u=r[i])&&(n[i]=u.__data__);return n}var c=U([]),s=_([]),l=_([]);if("function"==typeof n)for(;++i<a;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<a;)e(r=this[i],n);return s.enter=function(){return c},s.exit=function(){return l},s},pa.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},pa.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=R(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return _(u)},pa.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},pa.sort=function(n){n=D.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},pa.each=function(n){return P(this,function(t,e,r){n.call(t,t.__data__,e,r)})},pa.call=function(n){var t=Xo(arguments);return n.apply(t[0]=this,t),this},pa.empty=function(){return!this.node()},pa.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},pa.size=function(){var n=0;return this.each(function(){++n}),n};var da=[];Zo.selection.enter=U,Zo.selection.enter.prototype=da,da.append=pa.append,da.empty=pa.empty,da.node=pa.node,da.call=pa.call,da.size=pa.size,da.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var s=-1,l=u.length;++s<l;)(i=u[s])?(t.push(r[s]=e=n.call(u.parentNode,i.__data__,s,a)),e.__data__=i.__data__):t.push(null)}return _(o)},da.insert=function(n,t){return arguments.length<2&&(t=j(this)),pa.insert.call(this,n,t)},pa.transition=function(){for(var n,t,e=Ss||++Ns,r=[],u=ks||{time:Date.now(),ease:xu,delay:0,duration:250},i=-1,o=this.length;++i<o;){r.push(n=[]);for(var a=this[i],c=-1,s=a.length;++c<s;)(t=a[c])&&Po(t,c,e,u),n.push(t)}return qo(r,e)},pa.interrupt=function(){return this.each(H)},Zo.select=function(n){var t=["string"==typeof n?la(n,$o):n];return t.parentNode=Bo,_([t])},Zo.selectAll=function(n){var t=Xo("string"==typeof n?fa(n,$o):n);return t.parentNode=Bo,_([t])};var ma=Zo.select(Bo);pa.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(F(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(F(n,t,e))};var ya=Zo.map({mouseenter:"mouseover",mouseleave:"mouseout"});ya.forEach(function(n){"on"+n in $o&&ya.remove(n)});var xa="onselectstart"in $o?null:p(Bo.style,"userSelect"),Ma=0;Zo.mouse=function(n){return Z(n,x())};var _a=/WebKit/.test(Wo.navigator.userAgent)?-1:0;Zo.touches=function(n,t){return arguments.length<2&&(t=x().touches),t?Xo(t).map(function(t){var e=Z(n,t);return e.identifier=t.identifier,e}):[]},Zo.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",i)}function t(n,t,u,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-x[0],e=r[1]-x[1],p|=n|e,x=r,g({type:"drag",x:r[0]+s[0],y:r[1]+s[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&Zo.event.target===f),g({type:"dragend"}))}var s,l=this,f=Zo.event.target,h=l.parentNode,g=e.of(l,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=Zo.select(u()).on(i+d,a).on(o+d,c),y=I(),x=t(h,v);r?(s=r.apply(l,arguments),s=[s.x-x[0],s.y-x[1]]):s=[0,0],g({type:"dragstart"})}}var e=M(n,"drag","dragstart","dragend"),r=null,u=t(v,Zo.mouse,$,"mousemove","mouseup"),i=t(V,Zo.touch,X,"touchmove","touchend");return n.origin=function(t){return arguments.length?(r=t,n):r},Zo.rebind(n,e,"on")};var ba=Math.PI,wa=2*ba,Sa=ba/2,ka=1e-6,Ea=ka*ka,Aa=ba/180,Ca=180/ba,Na=Math.SQRT2,za=2,La=4;Zo.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=Q(v),o=i/(za*h)*(e*nt(Na*t+v)-K(v));return[r+o*s,u+o*l,i*e/Q(Na*t+v)]}return[r+n*s,u+n*l,i*Math.exp(Na*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],s=o-r,l=a-u,f=s*s+l*l,h=Math.sqrt(f),g=(c*c-i*i+La*f)/(2*i*za*h),p=(c*c-i*i-La*f)/(2*c*za*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Na;return e.duration=1e3*y,e},Zo.behavior.zoom=function(){function n(n){n.on(A,s).on(Ra+".zoom",f).on("dblclick.zoom",h).on(z,l)}function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}function r(n){S.k=Math.max(E[0],Math.min(E[1],n))}function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}function i(){_&&_.domain(x.range().map(function(n){return(n-S.x)/S.k}).map(x.invert)),w&&w.domain(b.range().map(function(n){return(n-S.y)/S.k}).map(b.invert))}function o(n){n({type:"zoomstart"})}function a(n){i(),n({type:"zoom",scale:S.k,translate:[S.x,S.y]})}function c(n){n({type:"zoomend"})}function s(){function n(){l=1,u(Zo.mouse(r),h),a(s)}function e(){f.on(C,null).on(N,null),g(l&&Zo.event.target===i),c(s)}var r=this,i=Zo.event.target,s=L.of(r,arguments),l=0,f=Zo.select(Wo).on(C,n).on(N,e),h=t(Zo.mouse(r)),g=I();H.call(r),o(s)}function l(){function n(){var n=Zo.touches(g);return h=S.k,n.forEach(function(n){n.identifier in v&&(v[n.identifier]=t(n))}),n}function e(){var t=Zo.event.target;Zo.select(t).on(M,i).on(_,f),b.push(t);for(var e=Zo.event.changedTouches,o=0,c=e.length;c>o;++o)v[e[o].identifier]=null;var s=n(),l=Date.now();if(1===s.length){if(500>l-m){var h=s[0],g=v[h.identifier];r(2*S.k),u(h,g),y(),a(p)}m=l}else if(s.length>1){var h=s[0],x=s[1],w=h[0]-x[0],k=h[1]-x[1];d=w*w+k*k}}function i(){for(var n,t,e,i,o=Zo.touches(g),c=0,s=o.length;s>c;++c,i=null)if(e=o[c],i=v[e.identifier]){if(t)break;n=e,t=i}if(i){var l=(l=e[0]-n[0])*l+(l=e[1]-n[1])*l,f=d&&Math.sqrt(l/d);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*h)}m=null,u(n,t),a(p)}function f(){if(Zo.event.touches.length){for(var t=Zo.event.changedTouches,e=0,r=t.length;r>e;++e)delete v[t[e].identifier];for(var u in v)return void n()}Zo.selectAll(b).on(x,null),w.on(A,s).on(z,l),k(),c(p)}var h,g=this,p=L.of(g,arguments),v={},d=0,x=".zoom-"+Zo.event.changedTouches[0].identifier,M="touchmove"+x,_="touchend"+x,b=[],w=Zo.select(g).on(A,null).on(z,e),k=I();H.call(g),e(),o(p)}function f(){var n=L.of(this,arguments);d?clearTimeout(d):(g=t(p=v||Zo.mouse(this)),H.call(this),o(n)),d=setTimeout(function(){d=null,c(n)},50),y(),r(Math.pow(2,.002*Ta())*S.k),u(p,g),a(n)}function h(){var n=L.of(this,arguments),e=Zo.mouse(this),i=t(e),s=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,Zo.event.shiftKey?Math.ceil(s)-1:Math.floor(s)+1)),u(e,i),a(n),c(n)}var g,p,v,d,m,x,_,b,w,S={x:0,y:0,k:1},k=[960,500],E=qa,A="mousedown.zoom",C="mousemove.zoom",N="mouseup.zoom",z="touchstart.zoom",L=M(n,"zoomstart","zoom","zoomend");return n.event=function(n){n.each(function(){var n=L.of(this,arguments),t=S;Ss?Zo.select(this).transition().each("start.zoom",function(){S=this.__chart__||{x:0,y:0,k:1},o(n)}).tween("zoom:zoom",function(){var e=k[0],r=k[1],u=e/2,i=r/2,o=Zo.interpolateZoom([(u-S.x)/S.k,(i-S.y)/S.k,e/S.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),c=e/r[2];this.__chart__=S={x:u-r[0]*c,y:i-r[1]*c,k:c},a(n)}}).each("end.zoom",function(){c(n)}):(this.__chart__=S,o(n),a(n),c(n))})},n.translate=function(t){return arguments.length?(S={x:+t[0],y:+t[1],k:S.k},i(),n):[S.x,S.y]},n.scale=function(t){return arguments.length?(S={x:S.x,y:S.y,k:+t},i(),n):S.k},n.scaleExtent=function(t){return arguments.length?(E=null==t?qa:[+t[0],+t[1]],n):E},n.center=function(t){return arguments.length?(v=t&&[+t[0],+t[1]],n):v},n.size=function(t){return arguments.length?(k=t&&[+t[0],+t[1]],n):k},n.x=function(t){return arguments.length?(_=t,x=t.copy(),S={x:0,y:0,k:1},n):_},n.y=function(t){return arguments.length?(w=t,b=t.copy(),S={x:0,y:0,k:1},n):w},Zo.rebind(n,L,"on")};var Ta,qa=[0,1/0],Ra="onwheel"in $o?(Ta=function(){return-Zo.event.deltaY*(Zo.event.deltaMode?120:1)},"wheel"):"onmousewheel"in $o?(Ta=function(){return Zo.event.wheelDelta},"mousewheel"):(Ta=function(){return-Zo.event.detail},"MozMousePixelScroll");Zo.color=et,et.prototype.toString=function(){return this.rgb()+""},Zo.hsl=rt;var Da=rt.prototype=new et;Da.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new rt(this.h,this.s,this.l/n)},Da.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new rt(this.h,this.s,n*this.l)},Da.rgb=function(){return ut(this.h,this.s,this.l)},Zo.hcl=it;var Pa=it.prototype=new et;Pa.brighter=function(n){return new it(this.h,this.c,Math.min(100,this.l+Ua*(arguments.length?n:1)))},Pa.darker=function(n){return new it(this.h,this.c,Math.max(0,this.l-Ua*(arguments.length?n:1)))},Pa.rgb=function(){return ot(this.h,this.c,this.l).rgb()},Zo.lab=at;var Ua=18,ja=.95047,Ha=1,Fa=1.08883,Oa=at.prototype=new et;Oa.brighter=function(n){return new at(Math.min(100,this.l+Ua*(arguments.length?n:1)),this.a,this.b)},Oa.darker=function(n){return new at(Math.max(0,this.l-Ua*(arguments.length?n:1)),this.a,this.b)},Oa.rgb=function(){return ct(this.l,this.a,this.b)},Zo.rgb=gt;var Ya=gt.prototype=new et;Ya.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new gt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new gt(u,u,u)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new gt(n*this.r,n*this.g,n*this.b)},Ya.hsl=function(){return yt(this.r,this.g,this.b)},Ya.toString=function(){return"#"+dt(this.r)+dt(this.g)+dt(this.b)};var Ia=Zo.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ia.forEach(function(n,t){Ia.set(n,pt(t))}),Zo.functor=bt,Zo.xhr=St(wt),Zo.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=kt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(l>=s)return o;if(u)return u=!1,i;var t=l;if(34===n.charCodeAt(t)){for(var e=t;e++<s;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}l=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++l):10===r&&(u=!0),n.substring(t+1,e).replace(/""/g,'"')}for(;s>l;){var r=n.charCodeAt(l++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(l)&&(++l,++a);else if(r!==c)continue;return n.substring(t,l-a)}return n.substring(t)}for(var r,u,i={},o={},a=[],s=n.length,l=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();(!t||(h=t(h,f++)))&&a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new h,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},Zo.csv=Zo.dsv(",","text/csv"),Zo.tsv=Zo.dsv(" ","text/tab-separated-values"),Zo.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=x().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return Z(n,r)};var Za,Va,Xa,$a,Ba,Wa=Wo[p(Wo,"requestAnimationFrame")]||function(n){setTimeout(n,17)};Zo.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Va?Va.n=i:Za=i,Va=i,Xa||($a=clearTimeout($a),Xa=1,Wa(At))},Zo.timer.flush=function(){Ct(),Nt()},Zo.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var Ja=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Lt);Zo.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=Zo.round(n,zt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),Ja[8+e/3]};var Ga=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,Ka=Zo.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=Zo.round(n,zt(n,t))).toFixed(Math.max(0,Math.min(20,zt(n*(1+1e-15),t))))}}),Qa=Zo.time={},nc=Date;Rt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){tc.setUTCDate.apply(this._,arguments)},setDay:function(){tc.setUTCDay.apply(this._,arguments)},setFullYear:function(){tc.setUTCFullYear.apply(this._,arguments)},setHours:function(){tc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){tc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){tc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){tc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){tc.setUTCSeconds.apply(this._,arguments)},setTime:function(){tc.setTime.apply(this._,arguments)}};var tc=Date.prototype;Qa.year=Dt(function(n){return n=Qa.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),Qa.years=Qa.year.range,Qa.years.utc=Qa.year.utc.range,Qa.day=Dt(function(n){var t=new nc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),Qa.days=Qa.day.range,Qa.days.utc=Qa.day.utc.range,Qa.dayOfYear=function(n){var t=Qa.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=Qa[n]=Dt(function(n){return(n=Qa.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=Qa.year(n).getDay();return Math.floor((Qa.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});Qa[n+"s"]=e.range,Qa[n+"s"].utc=e.utc.range,Qa[n+"OfYear"]=function(n){var e=Qa.year(n).getDay();return Math.floor((Qa.dayOfYear(n)+(e+t)%7)/7)}}),Qa.week=Qa.sunday,Qa.weeks=Qa.sunday.range,Qa.weeks.utc=Qa.sunday.utc.range,Qa.weekOfYear=Qa.sundayOfYear;var ec={"-":"",_:" ",0:"0"},rc=/^\s*\d+/,uc=/^%/;Zo.locale=function(n){return{numberFormat:Tt(n),timeFormat:Ut(n)}};var ic=Zo.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});Zo.format=ic.numberFormat,Zo.geo={},ue.prototype={s:0,t:0,add:function(n){ie(n,this.t,oc),ie(oc.s,this.s,this),this.s?this.t+=oc.t:this.s=oc.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var oc=new ue;Zo.geo.stream=function(n,t){n&&ac.hasOwnProperty(n.type)?ac[n.type](n,t):oe(n,t)};var ac={Feature:function(n,t){oe(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)oe(e[r].geometry,t)}},cc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){ae(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)ae(e[r],t,0)},Polygon:function(n,t){ce(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)ce(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)oe(e[r],t)}};Zo.geo.area=function(n){return sc=0,Zo.geo.stream(n,fc),sc};var sc,lc=new ue,fc={sphere:function(){sc+=4*ba},point:v,lineStart:v,lineEnd:v,polygonStart:function(){lc.reset(),fc.lineStart=se},polygonEnd:function(){var n=2*lc;sc+=0>n?4*ba+n:n,fc.lineStart=fc.lineEnd=fc.point=v}};Zo.geo.bounds=function(){function n(n,t){x.push(M=[l=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=le([t*Aa,e*Aa]);if(m){var u=he(m,r),i=[u[1],-u[0],0],o=he(i,u);ve(o),o=de(o);var c=t-p,s=c>0?1:-1,v=o[0]*Ca*s,d=ua(c)>180;if(d^(v>s*p&&s*t>v)){var y=o[1]*Ca;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>s*p&&s*t>v)){var y=-o[1]*Ca;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t):h>=l?(l>t&&(l=t),t>h&&(h=t)):t>p?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t)}else n(t,e);m=r,p=t}function e(){_.point=t}function r(){M[0]=l,M[1]=h,_.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ua(r)>180?r+(r>0?360:-360):r}else v=n,d=e;fc.point(n,e),t(n,e)}function i(){fc.lineStart()}function o(){u(v,d),fc.lineEnd(),ua(y)>ka&&(l=-(h=180)),M[0]=l,M[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function s(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var l,f,h,g,p,v,d,m,y,x,M,_={point:n,lineStart:e,lineEnd:r,polygonStart:function(){_.point=u,_.lineStart=i,_.lineEnd=o,y=0,fc.polygonStart()},polygonEnd:function(){fc.polygonEnd(),_.point=n,_.lineStart=e,_.lineEnd=r,0>lc?(l=-(h=180),f=-(g=90)):y>ka?g=90:-ka>y&&(f=-90),M[0]=l,M[1]=h}};return function(n){g=h=-(l=f=1/0),x=[],Zo.geo.stream(n,_);var t=x.length;if(t){x.sort(c);for(var e,r=1,u=x[0],i=[u];t>r;++r)e=x[r],s(e[0],u)||s(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e); - for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,l=e[0],h=u[1])}return x=M=null,1/0===l||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[l,f],[h,g]]}}(),Zo.geo.centroid=function(n){hc=gc=pc=vc=dc=mc=yc=xc=Mc=_c=bc=0,Zo.geo.stream(n,wc);var t=Mc,e=_c,r=bc,u=t*t+e*e+r*r;return Ea>u&&(t=mc,e=yc,r=xc,ka>gc&&(t=pc,e=vc,r=dc),u=t*t+e*e+r*r,Ea>u)?[0/0,0/0]:[Math.atan2(e,t)*Ca,G(r/Math.sqrt(u))*Ca]};var hc,gc,pc,vc,dc,mc,yc,xc,Mc,_c,bc,wc={sphere:v,point:ye,lineStart:Me,lineEnd:_e,polygonStart:function(){wc.lineStart=be},polygonEnd:function(){wc.lineStart=Me}},Sc=Ae(we,Te,Re,[-ba,-ba/2]),kc=1e9;Zo.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ue(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(Zo.geo.conicEqualArea=function(){return He(Fe)}).raw=Fe,Zo.geo.albers=function(){return Zo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},Zo.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=Zo.geo.albers(),o=Zo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=Zo.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var s=i.scale(),l=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[l-.455*s,f-.238*s],[l+.455*s,f+.238*s]]).stream(c).point,r=o.translate([l-.307*s,f+.201*s]).clipExtent([[l-.425*s+ka,f+.12*s+ka],[l-.214*s-ka,f+.234*s-ka]]).stream(c).point,u=a.translate([l-.205*s,f+.212*s]).clipExtent([[l-.214*s+ka,f+.166*s+ka],[l-.115*s-ka,f+.234*s-ka]]).stream(c).point,n},n.scale(1070)};var Ec,Ac,Cc,Nc,zc,Lc,Tc={point:v,lineStart:v,lineEnd:v,polygonStart:function(){Ac=0,Tc.lineStart=Oe},polygonEnd:function(){Tc.lineStart=Tc.lineEnd=Tc.point=v,Ec+=ua(Ac/2)}},qc={point:Ye,lineStart:v,lineEnd:v,polygonStart:v,polygonEnd:v},Rc={point:Ve,lineStart:Xe,lineEnd:$e,polygonStart:function(){Rc.lineStart=Be},polygonEnd:function(){Rc.point=Ve,Rc.lineStart=Xe,Rc.lineEnd=$e}};Zo.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),Zo.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Ec=0,Zo.geo.stream(n,u(Tc)),Ec},n.centroid=function(n){return pc=vc=dc=mc=yc=xc=Mc=_c=bc=0,Zo.geo.stream(n,u(Rc)),bc?[Mc/bc,_c/bc]:xc?[mc/xc,yc/xc]:dc?[pc/dc,vc/dc]:[0/0,0/0]},n.bounds=function(n){return zc=Lc=-(Cc=Nc=1/0),Zo.geo.stream(n,u(qc)),[[Cc,Nc],[zc,Lc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||Ge(n):wt,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new Ie:new We(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(Zo.geo.albersUsa()).context(null)},Zo.geo.transform=function(n){return{stream:function(t){var e=new Ke(t);for(var r in n)e[r]=n[r];return e}}},Ke.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},Zo.geo.projection=nr,Zo.geo.projectionMutator=tr,(Zo.geo.equirectangular=function(){return nr(rr)}).raw=rr.invert=rr,Zo.geo.rotation=function(n){function t(t){return t=n(t[0]*Aa,t[1]*Aa),t[0]*=Ca,t[1]*=Ca,t}return n=ir(n[0]%360*Aa,n[1]*Aa,n.length>2?n[2]*Aa:0),t.invert=function(t){return t=n.invert(t[0]*Aa,t[1]*Aa),t[0]*=Ca,t[1]*=Ca,t},t},ur.invert=rr,Zo.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=ir(-n[0]*Aa,-n[1]*Aa,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Ca,n[1]*=Ca}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=sr((t=+r)*Aa,u*Aa),n):t},n.precision=function(r){return arguments.length?(e=sr(t*Aa,(u=+r)*Aa),n):u},n.angle(90)},Zo.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Aa,u=n[1]*Aa,i=t[1]*Aa,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),s=Math.cos(u),l=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=s*l-c*f*a)*e),c*l+s*f*a)},Zo.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return Zo.range(Math.ceil(i/d)*d,u,d).map(h).concat(Zo.range(Math.ceil(s/m)*m,c,m).map(g)).concat(Zo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ua(n%d)>ka}).map(l)).concat(Zo.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ua(n%m)>ka}).map(f))}var e,r,u,i,o,a,c,s,l,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(s).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],s=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),s>c&&(t=s,s=c,c=t),n.precision(y)):[[i,s],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,l=fr(a,o,90),f=hr(r,e,y),h=fr(s,c,90),g=hr(i,u,y),n):y},n.majorExtent([[-180,-90+ka],[180,90-ka]]).minorExtent([[-180,-80-ka],[180,80+ka]])},Zo.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=gr,u=pr;return n.distance=function(){return Zo.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},Zo.geo.interpolate=function(n,t){return vr(n[0]*Aa,n[1]*Aa,t[0]*Aa,t[1]*Aa)},Zo.geo.length=function(n){return Dc=0,Zo.geo.stream(n,Pc),Dc};var Dc,Pc={sphere:v,point:v,lineStart:dr,lineEnd:v,polygonStart:v,polygonEnd:v},Uc=mr(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(Zo.geo.azimuthalEqualArea=function(){return nr(Uc)}).raw=Uc;var jc=mr(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},wt);(Zo.geo.azimuthalEquidistant=function(){return nr(jc)}).raw=jc,(Zo.geo.conicConformal=function(){return He(yr)}).raw=yr,(Zo.geo.conicEquidistant=function(){return He(xr)}).raw=xr;var Hc=mr(function(n){return 1/n},Math.atan);(Zo.geo.gnomonic=function(){return nr(Hc)}).raw=Hc,Mr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Sa]},(Zo.geo.mercator=function(){return _r(Mr)}).raw=Mr;var Fc=mr(function(){return 1},Math.asin);(Zo.geo.orthographic=function(){return nr(Fc)}).raw=Fc;var Oc=mr(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(Zo.geo.stereographic=function(){return nr(Oc)}).raw=Oc,br.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Sa]},(Zo.geo.transverseMercator=function(){var n=_r(br),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=br,Zo.geom={},Zo.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=bt(e),i=bt(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(Er),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var s=kr(a),l=kr(c),f=l[0]===s[0],h=l[l.length-1]===s[s.length-1],g=[];for(t=s.length-1;t>=0;--t)g.push(n[a[s[t]][2]]);for(t=+f;t<l.length-h;++t)g.push(n[a[l[t]][2]]);return g}var e=wr,r=Sr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},Zo.geom.polygon=function(n){return sa(n,Yc),n};var Yc=Zo.geom.polygon.prototype=[];Yc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Yc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Yc.clip=function(n){for(var t,e,r,u,i,o,a=Nr(n),c=-1,s=this.length-Nr(this),l=this[s-1];++c<s;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Ar(o,l,u)?(Ar(i,l,u)||n.push(Cr(i,o,l,u)),n.push(o)):Ar(i,l,u)&&n.push(Cr(i,o,l,u)),i=o;a&&n.push(n[0]),l=u}return n};var Ic,Zc,Vc,Xc,$c,Bc=[],Wc=[];Ur.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Hr),t.length},Wr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},Jr.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=nu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(Kr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Qr(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(Qr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Kr(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?nu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return n.C=!1,void 0;do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,Kr(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,Qr(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,Kr(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,Qr(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,Kr(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,Qr(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},Zo.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return tu(e(n),a).cells.forEach(function(e,a){var c=e.edges,s=e.site,l=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):s.x>=r&&s.x<=i&&s.y>=u&&s.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];l.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/ka)*ka,y:Math.round(o(n,t)/ka)*ka,i:t}})}var r=wr,u=Sr,i=r,o=u,a=Jc;return n?t(n):(t.links=function(n){return tu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return tu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Hr),c=-1,s=a.length,l=a[s-1].edge,f=l.l===o?l.r:l.l;++c<s;)u=l,i=f,l=a[c].edge,f=l.l===o?l.r:l.l,r<i.i&&r<f.i&&ru(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=bt(r=n),t):r},t.y=function(n){return arguments.length?(o=bt(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?Jc:n,t):a===Jc?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===Jc?null:a&&a[1]},t)};var Jc=[[-1e6,-1e6],[1e6,1e6]];Zo.geom.delaunay=function(n){return Zo.geom.voronoi().triangles(n)},Zo.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,l=n.y;if(null!=c)if(ua(c-e)+ua(l-r)<.01)s(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,s(n,f,c,l,u,i,o,a),s(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else s(n,t,e,r,u,i,o,a)}function s(n,t,e,r,u,o,a,c){var s=.5*(u+a),l=.5*(o+c),f=e>=s,h=r>=l,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=ou()),f?u=s:a=s,h?o=l:c=l,i(n,t,e,r,u,o,a,c)}var l,f,h,g,p,v,d,m,y,x=bt(a),M=bt(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)l=n[g],l.x<v&&(v=l.x),l.y<d&&(d=l.y),l.x>m&&(m=l.x),l.y>y&&(y=l.y),f.push(l.x),h.push(l.y);else for(g=0;p>g;++g){var _=+x(l=n[g],g),b=+M(l,g);v>_&&(v=_),d>b&&(d=b),_>m&&(m=_),b>y&&(y=b),f.push(_),h.push(b)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=ou();if(k.add=function(n){i(k,n,+x(n,++g),+M(n,g),v,d,m,y)},k.visit=function(n){au(n,k,v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=l=null,k}var o,a=wr,c=Sr;return(o=arguments.length)?(a=uu,c=iu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},Zo.interpolateRgb=cu,Zo.interpolateObject=su,Zo.interpolateNumber=lu,Zo.interpolateString=fu;var Gc=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Kc=new RegExp(Gc.source,"g");Zo.interpolate=hu,Zo.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ia.has(t)||/^(#|rgb\(|hsl\()/.test(t)?cu:fu:t instanceof et?cu:Array.isArray(t)?gu:"object"===e&&isNaN(t)?su:lu)(n,t)}],Zo.interpolateArray=gu;var Qc=function(){return wt},ns=Zo.map({linear:Qc,poly:Mu,quad:function(){return mu},cubic:function(){return yu},sin:function(){return _u},exp:function(){return bu},circle:function(){return wu},elastic:Su,back:ku,bounce:function(){return Eu}}),ts=Zo.map({"in":wt,out:vu,"in-out":du,"out-in":function(n){return du(vu(n))}});Zo.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.substring(0,t):n,r=t>=0?n.substring(t+1):"in";return e=ns.get(e)||Qc,r=ts.get(r)||wt,pu(r(e.apply(null,Vo.call(arguments,1))))},Zo.interpolateHcl=Au,Zo.interpolateHsl=Cu,Zo.interpolateLab=Nu,Zo.interpolateRound=zu,Zo.transform=function(n){var t=$o.createElementNS(Zo.ns.prefix.svg,"g");return(Zo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Lu(e?e.matrix:es)})(n)},Lu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var es={a:1,b:0,c:0,d:1,e:0,f:0};Zo.interpolateTransform=Du,Zo.layout={},Zo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(ju(n[e]));return t}},Zo.layout.chord=function(){function n(){var n,s,f,h,g,p={},v=[],d=Zo.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(s=0,g=-1;++g<i;)s+=u[h][g];v.push(s),m.push(Zo.range(i)),n+=s}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(wa-l*i)/n,s=0,h=-1;++h<i;){for(f=s,g=-1;++g<i;){var y=d[h],x=m[y][g],M=u[y][x],_=s,b=s+=M*n;p[y+"-"+x]={index:y,subindex:x,startAngle:_,endAngle:b,value:M}}r[y]={index:y,startAngle:f,endAngle:s,value:(s-f)/n},s+=l}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,s={},l=0;return s.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,s):u},s.padding=function(n){return arguments.length?(l=n,e=r=null,s):l},s.sortGroups=function(n){return arguments.length?(o=n,e=r=null,s):o},s.sortSubgroups=function(n){return arguments.length?(a=n,e=null,s):a},s.sortChords=function(n){return arguments.length?(c=n,e&&t(),s):c},s.chords=function(){return e||n(),e},s.groups=function(){return r||n(),r},s},Zo.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var s=t.charge/c;n.px-=i*s,n.py-=o*s}return!0}if(t.point&&c&&p>c){var s=t.pointCharge/c;n.px-=i*s,n.py-=o*s}}return!t.charge}}function t(n){n.px=Zo.event.x,n.py=Zo.event.y,a.resume()}var e,r,u,i,o,a={},c=Zo.dispatch("start","tick","end"),s=[1,1],l=.9,f=rs,h=us,g=-30,p=is,v=.1,d=.64,m=[],y=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,x,M,_=m.length,b=y.length;for(e=0;b>e;++e)a=y[e],f=a.source,h=a.target,x=h.x-f.x,M=h.y-f.y,(p=x*x+M*M)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,x*=p,M*=p,h.x-=x*(d=f.weight/(h.weight+f.weight)),h.y-=M*d,f.x+=x*(d=1-d),f.y+=M*d);if((d=r*v)&&(x=s[0]/2,M=s[1]/2,e=-1,d))for(;++e<_;)a=m[e],a.x+=(x-a.x)*d,a.y+=(M-a.y)*d;if(g)for(Vu(t=Zo.geom.quadtree(m),r,o),e=-1;++e<_;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<_;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*l,a.y-=(a.py-(a.py=a.y))*l);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(y=n,a):y},a.size=function(n){return arguments.length?(s=n,a):s},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(l=+n,a):l},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),Zo.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=y[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,s=o.length;++a<s;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,l=y.length,p=s[0],v=s[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;l>t;++t)r=y[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;l>t;++t)u[t]=+f.call(this,y[t],t);else for(t=0;l>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;l>t;++t)i[t]=+h.call(this,y[t],t);else for(t=0;l>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=Zo.behavior.drag().origin(wt).on("dragstart.force",Ou).on("drag.force",t).on("dragend.force",Yu)),arguments.length?(this.on("mouseover.force",Iu).on("mouseout.force",Zu).call(e),void 0):e},Zo.rebind(a,c,"on")};var rs=20,us=1,is=1/0;Zo.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(s=e.call(n,i,i.depth))&&(c=s.length)){for(var c,s,l;--c>=0;)o.push(l=s[c]),l.parent=i,l.depth=i.depth+1;r&&(i.value=0),i.children=s}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Bu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=Gu,e=Wu,r=Ju;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&($u(t,function(n){n.children&&(n.value=0)}),Bu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},Zo.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,s=-1;for(r=t.value?r/t.value:0;++s<o;)n(a=i[s],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=Zo.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Xu(e,r)},Zo.layout.pie=function(){function n(i){var o=i.map(function(e,r){return+t.call(n,e,r)}),a=+("function"==typeof r?r.apply(this,arguments):r),c=(("function"==typeof u?u.apply(this,arguments):u)-a)/Zo.sum(o),s=Zo.range(i.length);null!=e&&s.sort(e===os?function(n,t){return o[t]-o[n]}:function(n,t){return e(i[n],i[t])});var l=[];return s.forEach(function(n){var t;l[n]={data:i[n],value:t=o[n],startAngle:a,endAngle:a+=t*c}}),l}var t=Number,e=os,r=0,u=wa;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n};var os={};Zo.layout.stack=function(){function n(a,c){var s=a.map(function(e,r){return t.call(n,e,r)}),l=s.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,l,c);s=Zo.permute(s,f),l=Zo.permute(l,f);var h,g,p,v=r.call(n,l,c),d=s.length,m=s[0].length;for(g=0;m>g;++g)for(u.call(n,s[0][g],p=v[g],l[0][g][1]),h=1;d>h;++h)u.call(n,s[h][g],p+=l[h-1][g][1],l[h][g][1]);return a}var t=wt,e=ei,r=ri,u=ti,i=Qu,o=ni;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:as.get(t)||ei,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:cs.get(t)||ri,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var as=Zo.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(ui),i=n.map(ii),o=Zo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,s=[],l=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],s.push(e)):(c+=i[e],l.push(e));return l.reverse().concat(s)},reverse:function(n){return Zo.range(n.length).reverse()},"default":ei}),cs=Zo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,s,l=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=s=0,e=1;h>e;++e){for(t=0,u=0;l>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];l>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,s>c&&(s=c)}for(e=0;h>e;++e)g[e]-=s;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ri});Zo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],s=n.map(e,this),l=r.call(this,s,i),f=u.call(this,l,s,i),i=-1,h=s.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=s[i],a>=l[0]&&a<=l[1]&&(o=c[Zo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=si,u=ai;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=bt(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return ci(n,t)}:bt(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},Zo.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],s=u[1],l=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Bu(a,function(n){n.r=+l(n.value)}),Bu(a,pi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/s))/2;Bu(a,function(n){n.r+=f}),Bu(a,pi),Bu(a,function(n){n.r-=f})}return mi(a,c/2,s/2,t?1:1/Math.max(2*a.r/c,2*a.r/s)),o}var t,e=Zo.layout.hierarchy().sort(li),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Xu(n,e)},Zo.layout.tree=function(){function n(n,u){var l=o.call(this,n,u),f=l[0],h=t(f);if(Bu(h,e),h.parent.m=-h.z,$u(h,r),s)$u(f,i);else{var g=f,p=f,v=f;$u(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);$u(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return l}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){wi(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],s=u.m,l=i.m,f=o.m,h=c.m;o=_i(o),u=Mi(u),o&&u;)c=Mi(c),i=_i(i),i.a=n,r=o.z+f-u.z-s+a(o._,u._),r>0&&(bi(Si(o,n,e),n,r),s+=r,l+=r),f+=o.m,s+=u.m,h+=c.m,l+=i.m;o&&!_i(i)&&(i.t=o,i.m+=f-l),u&&!Mi(c)&&(c.t=u,c.m+=s-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=Zo.layout.hierarchy().sort(null).value(null),a=xi,c=[1,1],s=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(s=null==(c=t)?i:null,n):s?null:c},n.nodeSize=function(t){return arguments.length?(s=null==(c=t)?null:i,n):s?c:null},Xu(n,o)},Zo.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],s=0;Bu(c,function(n){var t=n.children;t&&t.length?(n.x=Ei(t),n.y=ki(t)):(n.x=o?s+=e(n,o):0,n.y=0,o=n)});var l=Ai(c),f=Ci(c),h=l.x-e(l,f)/2,g=f.x+e(f,l)/2;return Bu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=Zo.layout.hierarchy().sort(null).value(null),e=xi,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Xu(n,t)},Zo.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,s=f(e),l=[],h=i.slice(),p=1/0,v="slice"===g?s.dx:"dice"===g?s.dy:"slice-dice"===g?1&e.depth?s.dy:s.dx:Math.min(s.dx,s.dy);for(n(h,s.dx*s.dy/e.value),l.area=0;(c=h.length)>0;)l.push(o=h[c-1]),l.area+=o.area,"squarify"!==g||(a=r(l,v))<=p?(h.pop(),p=a):(l.area-=l.pop().area,u(l,v,s,!1),v=Math.min(s.dx,s.dy),l.length=l.area=0,p=1/0);l.length&&(u(l,v,s,!0),l.length=l.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,s=e.y,l=t?c(n.area/t):0;if(t==e.dx){for((r||l>e.dy)&&(l=e.dy);++i<o;)u=n[i],u.x=a,u.y=s,u.dy=l,a+=u.dx=Math.min(e.x+e.dx-a,l?c(u.area/l):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=l,e.dy-=l}else{for((r||l>e.dx)&&(l=e.dx);++i<o;)u=n[i],u.x=a,u.y=s,u.dx=l,s+=u.dy=Math.min(e.y+e.dy-s,l?c(u.area/l):0);u.z=!1,u.dy+=e.y+e.dy-s,e.x+=l,e.dx-=l}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=s[0],i.dy=s[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=Zo.layout.hierarchy(),c=Math.round,s=[1,1],l=null,f=Ni,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));return i.size=function(n){return arguments.length?(s=n,i):s},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ni(t):zi(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return zi(t,n)}if(!arguments.length)return l;var r;return f=null==(l=n)?Ni:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Xu(i,a)},Zo.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=Zo.random.normal.apply(Zo,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=Zo.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},Zo.scale={};var ss={floor:wt,ceil:wt};Zo.scale.linear=function(){return Ui([0,1],[0,1],hu,!1)};var ls={s:1,g:1,p:1,r:1,e:1};Zo.scale.log=function(){return Vi(Zo.scale.linear().domain([0,1]),10,!0,[1,10])};var fs=Zo.format(".0e"),hs={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};Zo.scale.pow=function(){return Xi(Zo.scale.linear(),1,[0,1])},Zo.scale.sqrt=function(){return Zo.scale.pow().exponent(.5)},Zo.scale.ordinal=function(){return Bi([],{t:"range",a:[[]]})},Zo.scale.category10=function(){return Zo.scale.ordinal().range(gs)},Zo.scale.category20=function(){return Zo.scale.ordinal().range(ps)},Zo.scale.category20b=function(){return Zo.scale.ordinal().range(vs)},Zo.scale.category20c=function(){return Zo.scale.ordinal().range(ds)};var gs=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(vt),ps=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(vt),vs=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(vt),ds=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(vt);Zo.scale.quantile=function(){return Wi([],[])},Zo.scale.quantize=function(){return Ji(0,1,[0,1])},Zo.scale.threshold=function(){return Gi([.5],[0,1])},Zo.scale.identity=function(){return Ki([0,1])},Zo.svg={},Zo.svg.arc=function(){function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+ms,a=u.apply(this,arguments)+ms,c=(o>a&&(c=o,o=a,a=c),a-o),s=ba>c?"0":"1",l=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a); - return c>=ys?n?"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"M0,"+n+"A"+n+","+n+" 0 1,0 0,"+-n+"A"+n+","+n+" 0 1,0 0,"+n+"Z":"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":n?"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L"+n*h+","+n*g+"A"+n+","+n+" 0 "+s+",0 "+n*l+","+n*f+"Z":"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L0,0"+"Z"}var t=Qi,e=no,r=to,u=eo;return n.innerRadius=function(e){return arguments.length?(t=bt(e),n):t},n.outerRadius=function(t){return arguments.length?(e=bt(t),n):e},n.startAngle=function(t){return arguments.length?(r=bt(t),n):r},n.endAngle=function(t){return arguments.length?(u=bt(t),n):u},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,i=(r.apply(this,arguments)+u.apply(this,arguments))/2+ms;return[Math.cos(i)*n,Math.sin(i)*n]},n};var ms=-Sa,ys=wa-ka;Zo.svg.line=function(){return ro(wt)};var xs=Zo.map({linear:uo,"linear-closed":io,step:oo,"step-before":ao,"step-after":co,basis:po,"basis-open":vo,"basis-closed":mo,bundle:yo,cardinal:fo,"cardinal-open":so,"cardinal-closed":lo,monotone:So});xs.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Ms=[0,2/3,1/3,0],_s=[0,1/3,2/3,0],bs=[0,1/6,2/3,1/6];Zo.svg.line.radial=function(){var n=ro(ko);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},ao.reverse=co,co.reverse=ao,Zo.svg.area=function(){return Eo(wt)},Zo.svg.area.radial=function(){var n=Eo(ko);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},Zo.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),s=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,s)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,s.r,s.p0)+r(s.r,s.p1,s.a1-s.a0)+u(s.r,s.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)+ms,l=s.call(n,u,r)+ms;return{r:i,a0:o,a1:l,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(l),i*Math.sin(l)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>ba)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=gr,o=pr,a=Ao,c=to,s=eo;return n.radius=function(t){return arguments.length?(a=bt(t),n):a},n.source=function(t){return arguments.length?(i=bt(t),n):i},n.target=function(t){return arguments.length?(o=bt(t),n):o},n.startAngle=function(t){return arguments.length?(c=bt(t),n):c},n.endAngle=function(t){return arguments.length?(s=bt(t),n):s},n},Zo.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=gr,e=pr,r=Co;return n.source=function(e){return arguments.length?(t=bt(e),n):t},n.target=function(t){return arguments.length?(e=bt(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},Zo.svg.diagonal.radial=function(){var n=Zo.svg.diagonal(),t=Co,e=n.projection;return n.projection=function(n){return arguments.length?e(No(t=n)):t},n},Zo.svg.symbol=function(){function n(n,r){return(ws.get(t.call(this,n,r))||To)(e.call(this,n,r))}var t=Lo,e=zo;return n.type=function(e){return arguments.length?(t=bt(e),n):t},n.size=function(t){return arguments.length?(e=bt(t),n):e},n};var ws=Zo.map({circle:To,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*As)),e=t*As;return"M0,"+-t+"L"+e+",0"+" 0,"+t+" "+-e+",0"+"Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/Es),e=t*Es/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/Es),e=t*Es/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});Zo.svg.symbolTypes=ws.keys();var Ss,ks,Es=Math.sqrt(3),As=Math.tan(30*Aa),Cs=[],Ns=0;Cs.call=pa.call,Cs.empty=pa.empty,Cs.node=pa.node,Cs.size=pa.size,Zo.transition=function(n){return arguments.length?Ss?n.transition():n:ma.transition()},Zo.transition.prototype=Cs,Cs.select=function(n){var t,e,r,u=this.id,i=[];n=b(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]);for(var c=this[o],s=-1,l=c.length;++s<l;)(r=c[s])&&(e=n.call(r,r.__data__,s,o))?("__data__"in r&&(e.__data__=r.__data__),Po(e,s,u,r.__transition__[u]),t.push(e)):t.push(null)}return qo(i,u)},Cs.selectAll=function(n){var t,e,r,u,i,o=this.id,a=[];n=w(n);for(var c=-1,s=this.length;++c<s;)for(var l=this[c],f=-1,h=l.length;++f<h;)if(r=l[f]){i=r.__transition__[o],e=n.call(r,r.__data__,f,c),a.push(t=[]);for(var g=-1,p=e.length;++g<p;)(u=e[g])&&Po(u,g,o,i),t.push(u)}return qo(a,o)},Cs.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=R(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return qo(u,this.id)},Cs.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):P(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Cs.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Du:hu,a=Zo.ns.qualify(n);return Ro(this,"attr."+n,t,a.local?i:u)},Cs.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=Zo.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Cs.style=function(n,t,e){function r(){this.style.removeProperty(n)}function u(t){return null==t?r:(t+="",function(){var r,u=Wo.getComputedStyle(this,null).getPropertyValue(n);return u!==t&&(r=hu(u,t),function(t){this.style.setProperty(n,r(t),e)})})}var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(t="");for(e in n)this.style(e,n[e],t);return this}e=""}return Ro(this,"style."+n,t,u)},Cs.styleTween=function(n,t,e){function r(r,u){var i=t.call(this,r,u,Wo.getComputedStyle(this,null).getPropertyValue(n));return i&&function(t){this.style.setProperty(n,i(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,r)},Cs.text=function(n){return Ro(this,"text",n,Do)},Cs.remove=function(){return this.each("end.transition",function(){var n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Cs.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof n&&(n=Zo.ease.apply(Zo,arguments)),P(this,function(e){e.__transition__[t].ease=n}))},Cs.delay=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].delay:P(this,"function"==typeof n?function(e,r,u){e.__transition__[t].delay=+n.call(e,e.__data__,r,u)}:(n=+n,function(e){e.__transition__[t].delay=n}))},Cs.duration=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].duration:P(this,"function"==typeof n?function(e,r,u){e.__transition__[t].duration=Math.max(1,n.call(e,e.__data__,r,u))}:(n=Math.max(1,n),function(e){e.__transition__[t].duration=n}))},Cs.each=function(n,t){var e=this.id;if(arguments.length<2){var r=ks,u=Ss;Ss=e,P(this,function(t,r,u){ks=t.__transition__[e],n.call(t,t.__data__,r,u)}),ks=r,Ss=u}else P(this,function(r){var u=r.__transition__[e];(u.event||(u.event=Zo.dispatch("start","end"))).on(n,t)});return this},Cs.transition=function(){for(var n,t,e,r,u=this.id,i=++Ns,o=[],a=0,c=this.length;c>a;a++){o.push(n=[]);for(var t=this[a],s=0,l=t.length;l>s;s++)(e=t[s])&&(r=Object.create(e.__transition__[u]),r.delay+=r.duration,Po(e,s,i,r)),n.push(e)}return qo(o,i)},Zo.svg.axis=function(){function n(n){n.each(function(){var n,s=Zo.select(this),l=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):wt:t,p=s.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",ka),d=Zo.transition(p.exit()).style("opacity",ka).remove(),m=Zo.transition(p.order()).style("opacity",1),y=Ti(f),x=s.selectAll(".domain").data([0]),M=(x.enter().append("path").attr("class","domain"),Zo.transition(x));v.append("line"),v.append("text");var _=v.select("line"),b=m.select("line"),w=p.select("text").text(g),S=v.select("text"),k=m.select("text");switch(r){case"bottom":n=Uo,_.attr("y2",u),S.attr("y",Math.max(u,0)+o),b.attr("x2",0).attr("y2",u),k.attr("x",0).attr("y",Math.max(u,0)+o),w.attr("dy",".71em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+i+"V0H"+y[1]+"V"+i);break;case"top":n=Uo,_.attr("y2",-u),S.attr("y",-(Math.max(u,0)+o)),b.attr("x2",0).attr("y2",-u),k.attr("x",0).attr("y",-(Math.max(u,0)+o)),w.attr("dy","0em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+-i+"V0H"+y[1]+"V"+-i);break;case"left":n=jo,_.attr("x2",-u),S.attr("x",-(Math.max(u,0)+o)),b.attr("x2",-u).attr("y2",0),k.attr("x",-(Math.max(u,0)+o)).attr("y",0),w.attr("dy",".32em").style("text-anchor","end"),M.attr("d","M"+-i+","+y[0]+"H0V"+y[1]+"H"+-i);break;case"right":n=jo,_.attr("x2",u),S.attr("x",Math.max(u,0)+o),b.attr("x2",u).attr("y2",0),k.attr("x",Math.max(u,0)+o).attr("y",0),w.attr("dy",".32em").style("text-anchor","start"),M.attr("d","M"+i+","+y[0]+"H0V"+y[1]+"H"+i)}if(f.rangeBand){var E=f,A=E.rangeBand()/2;l=f=function(n){return E(n)+A}}else l.rangeBand?l=f:d.call(n,f);v.call(n,l),m.call(n,f)})}var t,e=Zo.scale.linear(),r=zs,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Ls?t+"":zs,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var zs="bottom",Ls={top:1,right:1,bottom:1,left:1};Zo.svg.brush=function(){function n(i){i.each(function(){var i=Zo.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=i.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),i.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=i.selectAll(".resize").data(p,wt);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Ts[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,f=Zo.transition(i),h=Zo.transition(o);c&&(l=Ti(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),e(f)),s&&(l=Ti(s),h.attr("y",l[0]).attr("height",l[1]-l[0]),r(f)),t(f)})}function t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+l[+/e$/.test(n)]+","+f[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",l[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",l[1]-l[0])}function r(n){n.select(".extent").attr("y",f[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",f[1]-f[0])}function u(){function u(){32==Zo.event.keyCode&&(C||(x=null,z[0]-=l[1],z[1]-=f[1],C=2),y())}function p(){32==Zo.event.keyCode&&2==C&&(z[0]+=l[1],z[1]+=f[1],C=0,y())}function v(){var n=Zo.mouse(_),u=!1;M&&(n[0]+=M[0],n[1]+=M[1]),C||(Zo.event.altKey?(x||(x=[(l[0]+l[1])/2,(f[0]+f[1])/2]),z[0]=l[+(n[0]<x[0])],z[1]=f[+(n[1]<x[1])]):x=null),E&&d(n,c,0)&&(e(S),u=!0),A&&d(n,s,1)&&(r(S),u=!0),u&&(t(S),w({type:"brush",mode:C?"move":"resize"}))}function d(n,t,e){var r,u,a=Ti(t),c=a[0],s=a[1],p=z[e],v=e?f:l,d=v[1]-v[0];return C&&(c-=p,s-=d+p),r=(e?g:h)?Math.max(c,Math.min(s,n[e])):n[e],C?u=(r+=p)+d:(x&&(p=Math.max(c,Math.min(s,2*x[e]-r))),r>p?(u=r,r=p):u=p),v[0]!=r||v[1]!=u?(e?o=null:i=null,v[0]=r,v[1]=u,!0):void 0}function m(){v(),S.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),Zo.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),N(),w({type:"brushend"})}var x,M,_=this,b=Zo.select(Zo.event.target),w=a.of(_,arguments),S=Zo.select(_),k=b.datum(),E=!/^(n|s)$/.test(k)&&c,A=!/^(e|w)$/.test(k)&&s,C=b.classed("extent"),N=I(),z=Zo.mouse(_),L=Zo.select(Wo).on("keydown.brush",u).on("keyup.brush",p);if(Zo.event.changedTouches?L.on("touchmove.brush",v).on("touchend.brush",m):L.on("mousemove.brush",v).on("mouseup.brush",m),S.interrupt().selectAll("*").interrupt(),C)z[0]=l[0]-z[0],z[1]=f[0]-z[1];else if(k){var T=+/w$/.test(k),q=+/^n/.test(k);M=[l[1-T]-z[0],f[1-q]-z[1]],z[0]=l[T],z[1]=f[q]}else Zo.event.altKey&&(x=z.slice());S.style("pointer-events","none").selectAll(".resize").style("display",null),Zo.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),v()}var i,o,a=M(n,"brushstart","brush","brushend"),c=null,s=null,l=[0,0],f=[0,0],h=!0,g=!0,p=qs[0];return n.event=function(n){n.each(function(){var n=a.of(this,arguments),t={x:l,y:f,i:i,j:o},e=this.__chart__||t;this.__chart__=t,Ss?Zo.select(this).transition().each("start.brush",function(){i=e.i,o=e.j,l=e.x,f=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=gu(l,t.x),r=gu(f,t.y);return i=o=null,function(u){l=t.x=e(u),f=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){i=t.i,o=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,p=qs[!c<<1|!s],n):c},n.y=function(t){return arguments.length?(s=t,p=qs[!c<<1|!s],n):s},n.clamp=function(t){return arguments.length?(c&&s?(h=!!t[0],g=!!t[1]):c?h=!!t:s&&(g=!!t),n):c&&s?[h,g]:c?h:s?g:null},n.extent=function(t){var e,r,u,a,h;return arguments.length?(c&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),i=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(h=e,e=r,r=h),(e!=l[0]||r!=l[1])&&(l=[e,r])),s&&(u=t[0],a=t[1],c&&(u=u[1],a=a[1]),o=[u,a],s.invert&&(u=s(u),a=s(a)),u>a&&(h=u,u=a,a=h),(u!=f[0]||a!=f[1])&&(f=[u,a])),n):(c&&(i?(e=i[0],r=i[1]):(e=l[0],r=l[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(h=e,e=r,r=h))),s&&(o?(u=o[0],a=o[1]):(u=f[0],a=f[1],s.invert&&(u=s.invert(u),a=s.invert(a)),u>a&&(h=u,u=a,a=h))),c&&s?[[e,u],[r,a]]:c?[e,r]:s&&[u,a])},n.clear=function(){return n.empty()||(l=[0,0],f=[0,0],i=o=null),n},n.empty=function(){return!!c&&l[0]==l[1]||!!s&&f[0]==f[1]},Zo.rebind(n,a,"on")};var Ts={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},qs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Rs=Qa.format=ic.timeFormat,Ds=Rs.utc,Ps=Ds("%Y-%m-%dT%H:%M:%S.%LZ");Rs.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Ho:Ps,Ho.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Ho.toString=Ps.toString,Qa.second=Dt(function(n){return new nc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),Qa.seconds=Qa.second.range,Qa.seconds.utc=Qa.second.utc.range,Qa.minute=Dt(function(n){return new nc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),Qa.minutes=Qa.minute.range,Qa.minutes.utc=Qa.minute.utc.range,Qa.hour=Dt(function(n){var t=n.getTimezoneOffset()/60;return new nc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),Qa.hours=Qa.hour.range,Qa.hours.utc=Qa.hour.utc.range,Qa.month=Dt(function(n){return n=Qa.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),Qa.months=Qa.month.range,Qa.months.utc=Qa.month.utc.range;var Us=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],js=[[Qa.second,1],[Qa.second,5],[Qa.second,15],[Qa.second,30],[Qa.minute,1],[Qa.minute,5],[Qa.minute,15],[Qa.minute,30],[Qa.hour,1],[Qa.hour,3],[Qa.hour,6],[Qa.hour,12],[Qa.day,1],[Qa.day,2],[Qa.week,1],[Qa.month,1],[Qa.month,3],[Qa.year,1]],Hs=Rs.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",we]]),Fs={range:function(n,t,e){return Zo.range(Math.ceil(n/e)*e,+t,e).map(Oo)},floor:wt,ceil:wt};js.year=Qa.year,Qa.scale=function(){return Fo(Zo.scale.linear(),js,Hs)};var Os=js.map(function(n){return[n[0].utc,n[1]]}),Ys=Ds.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",we]]);Os.year=Qa.year.utc,Qa.scale.utc=function(){return Fo(Zo.scale.linear(),Os,Ys)},Zo.text=St(function(n){return n.responseText}),Zo.json=function(n,t){return kt(n,"application/json",Yo,t)},Zo.html=function(n,t){return kt(n,"text/html",Io,t)},Zo.xml=St(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(Zo):"object"==typeof module&&module.exports&&(module.exports=Zo),this.d3=Zo}();
\ No newline at end of file diff --git a/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html b/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html deleted file mode 100644 index be0b581c..00000000 --- a/framework/src/onos/utils/jdvue/src/main/resources/org/onlab/jdvue/index.html +++ /dev/null @@ -1,371 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <meta charset="utf-8"> - <title>TITLE_PLACEHOLDER</title> - <style> - - .node { - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - fill: #bbb; - } - - .link { - stroke: steelblue; - stroke-opacity: .4; - fill: none; - pointer-events: none; - } - - .node--focus { - font-weight: 700; - fill: #000; - } - - .node:hover { - fill: steelblue; - } - - .node:hover, - .node--source, - .node--target { - font-weight: 700; - } - - .node--source { - fill: #2ca02c; - } - - .node--target { - fill: #d59800; - } - - .link--source, - .link--target { - stroke-opacity: 1; - stroke-width: 3px; - } - - .link--source { - stroke: #d59800; - } - - .link--target { - stroke: #2ca02c; - } - - .link--cycle { - stroke: #ff0000; - } - - .summary { - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - position: fixed; - top: 32px; - right: 32px; - width: 192px; - background-color: #ffffff; - box-shadow: 2px 2px 4px 2px #777777; - padding: 5px; - } - - .details { - display: none; - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - position: fixed; - top: 220px; - right: 32px; - width: 192px; - background-color: #ffffff; - box-shadow: 2px 2px 4px 2px #777777; - padding: 5px; - } - - .shown { - display:block; - } - - .stat { - text-align: right; - width: 64px; - } - - .title { - font-size: 16px; - font-weight: bold; - } - - #package { - font-size: 14px; - font-weight: bold; - } - </style> -</head> -<body> - <div class="summary"> - <div class="title">Project TITLE_PLACEHOLDER</div> - <table> - <tr> - <td>Sources:</td> - <td id="sourceCount" class="stat"></td> - </tr> - <tr> - <td>Packages:</td> - <td id="packageCount" class="stat"></td> - </tr> - <tr> - <td>Cyclic Segments:</td> - <td id="segmentCount" class="stat"></td> - </tr> - <tr> - <td>Cycles:</td> - <td id="cycleCount" class="stat"></td> - </tr> - </table> - <div><hr size="1"></div> - <div><input type="checkbox"> Highlight cycles</input></div> - <div><input style="width: 95%" type="range" min="0" max="100" value="75"></div> - </div> - <div class="details"> - <div id="package">Package Details</div> - <table> - <tr> - <td>Sources:</td> - <td id="psourceCount" class="stat"></td> - </tr> - <tr> - <td>Dependents:</td> - <td id="pdependentCount" class="stat"></td> - </tr> - <tr> - <td>Cyclic Segments:</td> - <td id="psegmentCount" class="stat"></td> - </tr> - <tr> - <td>Cycles:</td> - <td id="pcycleCount" class="stat"></td> - </tr> - </table> - </div> -<script> -D3JS_PLACEHOLDER - - var catalog = -DATA_PLACEHOLDER - ; - - var diameter = 1000, - radius = diameter / 2, - innerRadius = radius - 300; - - var cluster = d3.layout.cluster() - .size([360, innerRadius]) - .sort(null) - .value(function(d) { return d.size; }); - - var bundle = d3.layout.bundle(); - - var line = d3.svg.line.radial() - .interpolate("bundle") - .tension(.75) - .radius(function(d) { return d.y; }) - .angle(function(d) { return d.x / 180 * Math.PI; }); - - var svg = d3.select("body").append("svg") - .attr("width", diameter) - .attr("height", diameter) - .append("g") - .attr("transform", "translate(" + radius + "," + radius + ")"); - - var link = svg.append("g").selectAll(".link"), - node = svg.append("g").selectAll(".node"), - cycles = {}, highlightCycles, selectedNode; - - function isCyclicLink(l) { - return highlightCycles && - (cycles[l.source.key + "-" + l.target.key] || cycles[l.target.key + "-" + l.source.key]); - } - - function isCyclicPackageLink(l, p) { - var key = l.source.key + "-" + l.target.key, - rKey = l.target.key + "-" + l.source.key; - return isCyclicLink(l) && (p.cycleSegments[key] || p.cycleSegments[rKey]); - } - - function refreshPaths() { - svg.selectAll("path.link").classed("link--cycle", isCyclicLink); - } - - function processCatalog() { - var nodes = cluster.nodes(packageHierarchy(catalog.packages)), - links = packageImports(nodes), - splines = bundle(links); - cycles = catalog.cycleSegments; - - d3.select("input[type=checkbox]").on("change", function() { - highlightCycles = this.checked; - refreshPaths(); - }); - - link = link - .data(splines) - .enter().append("path") - .each(function(d) { d.source = d[0], d.target = d[d.length - 1]; }) - .attr("class", "link") - .classed("link--cycle", isCyclicLink) - .attr("d", function(d, i) { return line(splines[i]); }); - - - node = node - .data(nodes.filter(function(n) { return !n.children; })) - .enter().append("text") - .attr("class", "node") - .attr("dy", ".31em") - .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" + (d.x < 180 ? "" : "rotate(180)"); }) - .style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; }) - .text(function(d) { return d.key; }) - .on("focus", processSelect) - .on("blur", processSelect); - - d3.select("input[type=range]").on("change", function() { - line.tension(this.value / 100); - svg.selectAll("path.link") - .data(splines) - .attr("d", function(d, i) { return line(splines[i]); }); - }); - - d3.select("#packageCount").text(catalog.summary.packages); - d3.select("#sourceCount").text(catalog.summary.sources); - d3.select("#segmentCount").text(catalog.summary.cycleSegments); - d3.select("#cycleCount").text(catalog.summary.cycles); - } - - function processSelect(d) { - if (selectedNode === d) { - deselected(d); - selectedNode = null; - - } else if (selectedNode) { - deselected(selectedNode); - selectedNode = null; - selected(d); - - } else { - selected(d); - selectedNode = d; - } - } - - function selected(d) { - node - .each(function(n) { n.target = n.source = false; }) - .classed("node--focus", function(n) { return n === d; }); - - link - .classed("link--cycle", function(l) { return isCyclicPackageLink(l, d); }) - .classed("link--target", function(l) { if (l.target === d) return l.source.source = true; }) - .classed("link--source", function(l) { if (l.source === d) return l.target.target = true; }) - .filter(function(l) { return l.target === d || l.source === d; }) - .each(function() { this.parentNode.appendChild(this); }); - - node - .classed("node--target", function(n) { return n.target; }) - .classed("node--source", function(n) { return n.source; }); - - d3.select("#psourceCount").text(d.size); - d3.select("#pdependentCount").text(d.imports.length); - d3.select("#psegmentCount").text(d.cycleSegmentCount); - d3.select("#pcycleCount").text(d.cycleCount); - d3.select(".details").classed("shown", function() { return true; }); - } - - function deselected(d) { - link - .classed("link--cycle", isCyclicLink) - .classed("link--target", false) - .classed("link--source", false); - - node - .classed("node--target", false) - .classed("node--source", false) - .classed("node--focus", false); - d3.select(".details").classed("shown", function() { return false; }); - } - - d3.select(self.frameElement).style("height", diameter + "px"); - - // Lazily construct the package hierarchy. - function packageHierarchy(packages) { - var map = {}, cnt = 0; - - // Builds the structure top-down to the specified leaf or until - // another leaf in which case hook this leaf to the same parent - function buildHierarchy(leaf, i) { - var leafName = leaf.name, - node, name, parent = map[""], start = 0; - while (start < leafName.length) { - name = parentName(leafName, start); - node = map[name]; - if (!node) { - node = map[name] = parentNode(name, parent); - parent.children.push(node); - - } else if (node.imports) { - leaf.parent = parent; - parent.children.push(leaf); - break; - } - parent = node; - start = name.length + 1; - } - } - - function parentNode(name, parent) { - return {name: name, parent: parent, key: name, children: []}; - } - - function parentName(leafName, start) { - var i = leafName.indexOf(".", start); - return i > 0 ? leafName.substring(0, i) : leafName; - } - - // First populate all packages as leafs - packages.forEach(function(d) { - map[d.name] = d; - d.key = d.name; - }); - - // Next synthesize the intermediate structure, by-passing any leafs - map[""] = parentNode("", null); - var i = 0; - packages.forEach(function(d) { - buildHierarchy(d, i++); - }); - - return map[""]; - } - - // Return a list of imports for the given array of nodes. - function packageImports(nodes) { - var map = {}, - imports = []; - - // Compute a map from name to node. - nodes.forEach(function(d) { - map[d.name] = d; - }); - - // For each import, construct a link from the source to target node. - nodes.forEach(function(d) { - if (d.imports) d.imports.forEach(function(i) { - imports.push({source: map[d.name], target: map[i]}); - }); - }); - - return imports; - } - - processCatalog(); -</script> -</body> -</html> diff --git a/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/CatalogTest.java b/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/CatalogTest.java deleted file mode 100644 index b792abcc..00000000 --- a/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/CatalogTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import org.junit.Test; -import org.onlab.jdvue.Catalog; -import org.onlab.jdvue.JavaPackage; -import org.onlab.jdvue.JavaSource; - -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -/** - * Unit test for the source catalog. - * - * @author Thomas Vachuska - */ -public class CatalogTest { - - @Test - public void basics() throws IOException { - Catalog cat = new Catalog(); - cat.load("src/test/resources/catalog.db"); - cat.analyze(); - - assertEquals("incorrect package count", 12, cat.getPackages().size()); - assertEquals("incorrect source count", 14, cat.getSources().size()); - - JavaPackage pkg = cat.getPackage("k"); - assertNotNull("package should be found", pkg); - - JavaSource src = cat.getSource("k.K"); - assertNotNull("source should be found", src); - - assertEquals("incorrect package source count", 1, pkg.getSources().size()); - assertEquals("incorrect package dependency count", 1, pkg.getDependencies().size()); - assertEquals("incorrect package cycle count", 3, cat.getPackageCycles(pkg).size()); - - assertEquals("incorrect segment count", 11, cat.getCycleSegments().size()); - assertEquals("incorrect cycle count", 5, cat.getCycles().size()); - } - -} diff --git a/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyCycleTest.java b/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyCycleTest.java deleted file mode 100644 index 895c713f..00000000 --- a/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyCycleTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import org.junit.Test; -import org.onlab.jdvue.DependencyCycle; -import org.onlab.jdvue.JavaPackage; - -import java.util.Arrays; - -import static org.junit.Assert.*; - -/** - * Unit test for the dependency cycle entity. - * - * @author Thomas Vachuska - */ -public class DependencyCycleTest { - - @Test - public void normalize() { - JavaPackage x = new JavaPackage("x"); - JavaPackage y = new JavaPackage("y"); - JavaPackage z = new JavaPackage("z"); - - DependencyCycle a = new DependencyCycle(Arrays.asList(new JavaPackage[] {x, y, z}), x); - DependencyCycle b = new DependencyCycle(Arrays.asList(new JavaPackage[] {y, z, x}), y); - DependencyCycle c = new DependencyCycle(Arrays.asList(new JavaPackage[] {z, x, y}), z); - - assertEquals("incorrect normalization", a, b); - assertEquals("incorrect normalization", a, c); - } - - @Test - public void testToString() { - JavaPackage x = new JavaPackage("x"); - JavaPackage y = new JavaPackage("y"); - JavaPackage z = new JavaPackage("z"); - - DependencyCycle a = new DependencyCycle(Arrays.asList(new JavaPackage[] {x, y, z}), x); - assertEquals("incorrect toString", "[x, y, z]", a.toShortString()); - assertEquals("incorrect toString", - "DependencyCycle{cycle=[" + - "JavaPackage{name=x, sources=0, dependencies=0}, " + - "JavaPackage{name=y, sources=0, dependencies=0}, " + - "JavaPackage{name=z, sources=0, dependencies=0}]}", - a.toString()); - } -} diff --git a/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyTest.java b/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyTest.java deleted file mode 100644 index 94740dae..00000000 --- a/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; -import org.onlab.jdvue.Dependency; -import org.onlab.jdvue.JavaPackage; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -/** - * Unit test for the dependency entity. - * - * @author Thomas Vachuska - */ -public class DependencyTest { - - @Test - public void basics() { - JavaPackage x = new JavaPackage("x"); - JavaPackage y = new JavaPackage("y"); - - new EqualsTester() - .addEqualityGroup(new Dependency(x, y), new Dependency(x, y)) - .addEqualityGroup(new Dependency(y, x), new Dependency(y, x)) - .testEquals(); - } - -} diff --git a/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyViewerTest.java b/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyViewerTest.java deleted file mode 100644 index 0937c068..00000000 --- a/framework/src/onos/utils/jdvue/src/test/java/org/onlab/jdvue/DependencyViewerTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.jdvue; - -import org.junit.Test; -import org.onlab.jdvue.DependencyViewer; - -import java.io.FileInputStream; -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.onlab.jdvue.DependencyViewer.slurp; - -/** - * Unit test for the dependency viewer. - * - * @author Thomas Vachuska - */ -public class DependencyViewerTest { - - @Test - public void basics() throws IOException { - DependencyViewer.main(new String[]{"src/test/resources/catalog"}); - - String expected = slurp(new FileInputStream("src/test/resources/expected.html")); - String actual = slurp(new FileInputStream("src/test/resources/catalog.html")); - - // FIXME: add more manageable assertions here -// assertEquals("incorrect html", expected, actual); - } - -} diff --git a/framework/src/onos/utils/jdvue/src/test/resources/catalog.db b/framework/src/onos/utils/jdvue/src/test/resources/catalog.db deleted file mode 100644 index 156eeec9..00000000 --- a/framework/src/onos/utils/jdvue/src/test/resources/catalog.db +++ /dev/null @@ -1,33 +0,0 @@ -src/main/java/a/A.java:package a; -src/main/java/a/A.java:import b.B; -src/main/java/a/A2.java:package a; -src/main/java/a/A2.java:import c.C; -src/main/java/b/B.java:package b; -src/main/java/b/B.java:import c.C; -src/main/java/c/C.java:package c; - -src/main/java/x/X.java:package x; -src/main/java/x/X.java:import y.Y; -src/main/java/y/Y.java:package y; -src/main/java/y/Y.java:import z.Z; -src/main/java/z/Z.java:package z; -src/main/java/z/Z.java:import x.X; - -src/main/java/u/U.java:package u; -src/main/java/u/U.java:import v.V; -src/main/java/u/U2.java:package u; -src/main/java/u/U2.java:import v.V; -src/main/java/v/V.java:package v; -src/main/java/v/V.java:import u.U; - -src/main/java/k/K.java:package k; -src/main/java/k/K.java:import l.L; -src/main/java/l/L.java:package l; -src/main/java/l/L.java:import k.K; -src/main/java/l/L.java:import m.M; -src/main/java/l/L.java:import n.N; -src/main/java/m/M.java:package m; -src/main/java/m/M.java:import n.N; -src/main/java/n/N.java:package n; -src/main/java/n/N.java:import k.K; - diff --git a/framework/src/onos/utils/jdvue/src/test/resources/catalog.html b/framework/src/onos/utils/jdvue/src/test/resources/catalog.html deleted file mode 100644 index f3813596..00000000 --- a/framework/src/onos/utils/jdvue/src/test/resources/catalog.html +++ /dev/null @@ -1,376 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <meta charset="utf-8"> - <title>src/test/resources/catalog</title> - <style> - - .node { - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - fill: #bbb; - } - - .link { - stroke: steelblue; - stroke-opacity: .4; - fill: none; - pointer-events: none; - } - - .node--focus { - font-weight: 700; - fill: #000; - } - - .node:hover { - fill: steelblue; - } - - .node:hover, - .node--source, - .node--target { - font-weight: 700; - } - - .node--source { - fill: #2ca02c; - } - - .node--target { - fill: #d59800; - } - - .link--source, - .link--target { - stroke-opacity: 1; - stroke-width: 3px; - } - - .link--source { - stroke: #d59800; - } - - .link--target { - stroke: #2ca02c; - } - - .link--cycle { - stroke: #ff0000; - } - - .summary { - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - position: fixed; - top: 32px; - right: 32px; - width: 192px; - background-color: #ffffff; - box-shadow: 2px 2px 4px 2px #777777; - padding: 5px; - } - - .details { - display: none; - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - position: fixed; - top: 220px; - right: 32px; - width: 192px; - background-color: #ffffff; - box-shadow: 2px 2px 4px 2px #777777; - padding: 5px; - } - - .shown { - display:block; - } - - .stat { - text-align: right; - width: 64px; - } - - .title { - font-size: 16px; - font-weight: bold; - } - - #package { - font-size: 14px; - font-weight: bold; - } - </style> -</head> -<body> - <div class="summary"> - <div class="title">Project src/test/resources/catalog</div> - <table> - <tr> - <td>Sources:</td> - <td id="sourceCount" class="stat"></td> - </tr> - <tr> - <td>Packages:</td> - <td id="packageCount" class="stat"></td> - </tr> - <tr> - <td>Cyclic Segments:</td> - <td id="segmentCount" class="stat"></td> - </tr> - <tr> - <td>Cycles:</td> - <td id="cycleCount" class="stat"></td> - </tr> - </table> - <div><hr size="1"></div> - <div><input type="checkbox"> Highlight cycles</input></div> - <div><input style="width: 95%" type="range" min="0" max="100" value="75"></div> - </div> - <div class="details"> - <div id="package">Package Details</div> - <table> - <tr> - <td>Sources:</td> - <td id="psourceCount" class="stat"></td> - </tr> - <tr> - <td>Dependents:</td> - <td id="pdependentCount" class="stat"></td> - </tr> - <tr> - <td>Cyclic Segments:</td> - <td id="psegmentCount" class="stat"></td> - </tr> - <tr> - <td>Cycles:</td> - <td id="pcycleCount" class="stat"></td> - </tr> - </table> - </div> -<script> -!function(){function n(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function t(n){return null!=n&&!isNaN(n)}function e(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function r(n){return n.length}function u(n){for(var t=1;n*t%1;)t*=10;return t}function i(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function o(){}function a(n){return ia+n in this}function c(n){return n=ia+n,n in this&&delete this[n]}function s(){var n=[];return this.forEach(function(t){n.push(t)}),n}function l(){var n=0;for(var t in this)t.charCodeAt(0)===oa&&++n;return n}function f(){for(var n in this)if(n.charCodeAt(0)===oa)return!1;return!0}function h(){}function g(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function p(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=aa.length;r>e;++e){var u=aa[e]+t;if(u in n)return u}}function v(){}function d(){}function m(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new o;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function y(){Zo.event.preventDefault()}function x(){for(var n,t=Zo.event;n=t.sourceEvent;)t=n;return t}function M(n){for(var t=new d,e=0,r=arguments.length;++e<r;)t[arguments[e]]=m(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=Zo.event;u.target=n,Zo.event=u,t[u.type].apply(e,r)}finally{Zo.event=i}}},t}function _(n){return sa(n,pa),n}function b(n){return"function"==typeof n?n:function(){return la(n,this)}}function w(n){return"function"==typeof n?n:function(){return fa(n,this)}}function S(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=Zo.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function k(n){return n.trim().replace(/\s+/g," ")}function E(n){return new RegExp("(?:^|\\s+)"+Zo.requote(n)+"(?:\\s+|$)","g")}function A(n){return(n+"").trim().split(/^|\s+/)}function C(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=A(n).map(N);var u=n.length;return"function"==typeof t?r:e}function N(n){var t=E(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",k(u+" "+n))):e.setAttribute("class",k(u.replace(t," ")))}}function z(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function L(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function T(n){return"function"==typeof n?n:(n=Zo.ns.qualify(n)).local?function(){return this.ownerDocument.createElementNS(n.space,n.local)}:function(){return this.ownerDocument.createElementNS(this.namespaceURI,n)}}function q(n){return{__data__:n}}function R(n){return function(){return ga(this,n)}}function D(t){return arguments.length||(t=n),function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}}function P(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function U(n){return sa(n,da),n}function j(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function H(){var n=this.__transition__;n&&++n.active}function F(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,Xo(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+Zo.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=O;a>0&&(n=n.substring(0,a));var s=ya.get(n);return s&&(n=s,c=Y),a?t?u:r:t?v:i}function O(n,t){return function(e){var r=Zo.event;Zo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{Zo.event=r}}}function Y(n,t){var e=O(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function I(){var n=".dragsuppress-"+ ++Ma,t="click"+n,e=Zo.select(Wo).on("touchmove"+n,y).on("dragstart"+n,y).on("selectstart"+n,y);if(xa){var r=Bo.style,u=r[xa];r[xa]="none"}return function(i){function o(){e.on(t,null)}e.on(n,null),xa&&(r[xa]=u),i&&(e.on(t,function(){y(),o()},!0),setTimeout(o,0))}}function Z(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>_a&&(Wo.scrollX||Wo.scrollY)){e=Zo.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var u=e[0][0].getScreenCTM();_a=!(u.f||u.e),e.remove()}return _a?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}function V(){return Zo.event.changedTouches[0].identifier}function X(){return Zo.event.target}function $(){return Wo}function B(n){return n>0?1:0>n?-1:0}function W(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function J(n){return n>1?0:-1>n?ba:Math.acos(n)}function G(n){return n>1?Sa:-1>n?-Sa:Math.asin(n)}function K(n){return((n=Math.exp(n))-1/n)/2}function Q(n){return((n=Math.exp(n))+1/n)/2}function nt(n){return((n=Math.exp(2*n))-1)/(n+1)}function tt(n){return(n=Math.sin(n/2))*n}function et(){}function rt(n,t,e){return this instanceof rt?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof rt?new rt(n.h,n.s,n.l):mt(""+n,yt,rt):new rt(n,t,e)}function ut(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new gt(u(n+120),u(n),u(n-120))}function it(n,t,e){return this instanceof it?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof it?new it(n.h,n.c,n.l):n instanceof at?st(n.l,n.a,n.b):st((n=xt((n=Zo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new it(n,t,e)}function ot(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new at(e,Math.cos(n*=Aa)*t,Math.sin(n)*t)}function at(n,t,e){return this instanceof at?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof at?new at(n.l,n.a,n.b):n instanceof it?ot(n.l,n.c,n.h):xt((n=gt(n)).r,n.g,n.b):new at(n,t,e)}function ct(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=lt(u)*ja,r=lt(r)*Ha,i=lt(i)*Fa,new gt(ht(3.2404542*u-1.5371385*r-.4985314*i),ht(-.969266*u+1.8760108*r+.041556*i),ht(.0556434*u-.2040259*r+1.0572252*i))}function st(n,t,e){return n>0?new it(Math.atan2(e,t)*Ca,Math.sqrt(t*t+e*e),n):new it(0/0,0/0,n)}function lt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function ft(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function ht(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function gt(n,t,e){return this instanceof gt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof gt?new gt(n.r,n.g,n.b):mt(""+n,gt,ut):new gt(n,t,e)}function pt(n){return new gt(n>>16,255&n>>8,255&n)}function vt(n){return pt(n)+""}function dt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function mt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(_t(u[0]),_t(u[1]),_t(u[2]))}return(i=Ia.get(n))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.substring(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function yt(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new rt(r,u,c)}function xt(n,t,e){n=Mt(n),t=Mt(t),e=Mt(e);var r=ft((.4124564*n+.3575761*t+.1804375*e)/ja),u=ft((.2126729*n+.7151522*t+.072175*e)/Ha),i=ft((.0193339*n+.119192*t+.9503041*e)/Fa);return at(116*u-16,500*(r-u),200*(u-i))}function Mt(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function _t(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function bt(n){return"function"==typeof n?n:function(){return n}}function wt(n){return n}function St(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),kt(t,e,n,r)}}function kt(n,t,e,r){function u(){var n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return o.error.call(i,r),void 0}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=Zo.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,s=null;return!Wo.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=Zo.event;Zo.event=n;try{o.progress.call(i,c)}finally{Zo.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(s=n,i):s},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(Xo(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var l in a)c.setRequestHeader(l,a[l]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=s&&(c.responseType=s),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},Zo.rebind(i,o,"on"),null==r?i:i.get(Et(r))}function Et(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function At(){var n=Ct(),t=Nt()-n;t>24?(isFinite(t)&&(clearTimeout($a),$a=setTimeout(At,t)),Xa=0):(Xa=1,Wa(At))}function Ct(){var n=Date.now();for(Ba=Za;Ba;)n>=Ba.t&&(Ba.f=Ba.c(n-Ba.t)),Ba=Ba.n;return n}function Nt(){for(var n,t=Za,e=1/0;t;)t.f?t=n?n.n=t.n:Za=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Va=n,e}function zt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Lt(n,t){var e=Math.pow(10,3*ua(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Tt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r?function(n){for(var t=n.length,u=[],i=0,o=r[0];t>0&&o>0;)u.push(n.substring(t-=o,t+o)),o=r[i=(i+1)%r.length];return u.reverse().join(e)}:wt;return function(n){var e=Ga.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"",c=e[4]||"",s=e[5],l=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1;switch(h&&(h=+h.substring(1)),(s||"0"===r&&"="===o)&&(s=r="0",o="=",f&&(l-=Math.floor((l-1)/4))),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=Ka.get(g)||qt;var y=s&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):a;if(0>p){var c=Zo.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x=n.lastIndexOf("."),M=0>x?n:n.substring(0,x),_=0>x?"":t+n.substring(x+1);!s&&f&&(M=i(M));var b=v.length+M.length+_.length+(y?0:u.length),w=l>b?new Array(b=l-b+1).join(r):"";return y&&(M=i(w+M)),u+=v,n=M+_,("<"===o?u+n+w:">"===o?w+u+n:"^"===o?w.substring(0,b>>=1)+u+n+w.substring(b):u+(y?n:w+n))+e}}}function qt(n){return n+""}function Rt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Dt(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new nc(e-1)),1),e}function i(n,e){return t(n=new nc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{nc=Rt;var r=new Rt;return r._=n,o(r,t,e)}finally{nc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Pt(n);return c.floor=c,c.round=Pt(r),c.ceil=Pt(u),c.offset=Pt(i),c.range=a,n}function Pt(n){return function(t,e){try{nc=Rt;var r=new Rt;return r._=t,n(r,e)._}finally{nc=Date}}}function Ut(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.substring(c,a)),null!=(u=ec[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=C[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.substring(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&nc!==Rt,o=new(i?Rt:nc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+Math.floor(r.Z/100),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,s=e.length;c>a;){if(r>=s)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=N[o in ec?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){b.lastIndex=0;var r=b.exec(t.substring(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){M.lastIndex=0;var r=M.exec(t.substring(e));return r?(n.w=_.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.substring(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.substring(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,C.c.toString(),t,r)}function c(n,t,r){return e(n,C.x.toString(),t,r)}function s(n,t,r){return e(n,C.X.toString(),t,r)}function l(n,t,e){var r=x.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{nc=Rt;var t=new nc;return t._=n,r(t)}finally{nc=Date}}var r=t(n);return e.parse=function(n){try{nc=Rt;var t=r.parse(n);return t&&t._}finally{nc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=re;var x=Zo.map(),M=Ht(v),_=Ft(v),b=Ht(d),w=Ft(d),S=Ht(m),k=Ft(m),E=Ht(y),A=Ft(y);p.forEach(function(n,t){x.set(n.toLowerCase(),t)});var C={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return jt(n.getDate(),t,2)},e:function(n,t){return jt(n.getDate(),t,2)},H:function(n,t){return jt(n.getHours(),t,2)},I:function(n,t){return jt(n.getHours()%12||12,t,2)},j:function(n,t){return jt(1+Qa.dayOfYear(n),t,3)},L:function(n,t){return jt(n.getMilliseconds(),t,3)},m:function(n,t){return jt(n.getMonth()+1,t,2)},M:function(n,t){return jt(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return jt(n.getSeconds(),t,2)},U:function(n,t){return jt(Qa.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return jt(Qa.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return jt(n.getFullYear()%100,t,2)},Y:function(n,t){return jt(n.getFullYear()%1e4,t,4)},Z:te,"%":function(){return"%"}},N={a:r,A:u,b:i,B:o,c:a,d:Wt,e:Wt,H:Gt,I:Gt,j:Jt,L:ne,m:Bt,M:Kt,p:l,S:Qt,U:Yt,w:Ot,W:It,x:c,X:s,y:Vt,Y:Zt,Z:Xt,"%":ee};return t}function jt(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Ht(n){return new RegExp("^(?:"+n.map(Zo.requote).join("|")+")","i")}function Ft(n){for(var t=new o,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Ot(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Yt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e));return r?(n.U=+r[0],e+r[0].length):-1}function It(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e));return r?(n.W=+r[0],e+r[0].length):-1}function Zt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Vt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.y=$t(+r[0]),e+r[0].length):-1}function Xt(n,t,e){return/^[+-]\d{4}$/.test(t=t.substring(e,e+5))?(n.Z=-t,e+5):-1}function $t(n){return n+(n>68?1900:2e3)}function Bt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Wt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function Jt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function Gt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function Kt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function Qt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ne(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function te(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(ua(t)/60),u=ua(t)%60;return e+jt(r,"0",2)+jt(u,"0",2)}function ee(n,t,e){uc.lastIndex=0;var r=uc.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function re(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ue(){}function ie(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function oe(n,t){n&&cc.hasOwnProperty(n.type)&&cc[n.type](n,t)}function ae(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function ce(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)ae(n[e],t,1);t.polygonEnd()}function se(){function n(n,t){n*=Aa,t=t*Aa/2+ba/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),s=Math.sin(t),l=i*s,f=u*c+l*Math.cos(a),h=l*o*Math.sin(a);lc.add(Math.atan2(h,f)),r=n,u=c,i=s}var t,e,r,u,i;fc.point=function(o,a){fc.point=n,r=(t=o)*Aa,u=Math.cos(a=(e=a)*Aa/2+ba/4),i=Math.sin(a)},fc.lineEnd=function(){n(t,e)}}function le(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function fe(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function he(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function ge(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function pe(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function ve(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function de(n){return[Math.atan2(n[1],n[0]),G(n[2])]}function me(n,t){return ua(n[0]-t[0])<ka&&ua(n[1]-t[1])<ka}function ye(n,t){n*=Aa;var e=Math.cos(t*=Aa);xe(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function xe(n,t,e){++hc,pc+=(n-pc)/hc,vc+=(t-vc)/hc,dc+=(e-dc)/hc}function Me(){function n(n,u){n*=Aa;var i=Math.cos(u*=Aa),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),s=Math.atan2(Math.sqrt((s=e*c-r*a)*s+(s=r*o-t*c)*s+(s=t*a-e*o)*s),t*o+e*a+r*c);gc+=s,mc+=s*(t+(t=o)),yc+=s*(e+(e=a)),xc+=s*(r+(r=c)),xe(t,e,r)}var t,e,r;wc.point=function(u,i){u*=Aa;var o=Math.cos(i*=Aa);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),wc.point=n,xe(t,e,r)}}function _e(){wc.point=ye}function be(){function n(n,t){n*=Aa;var e=Math.cos(t*=Aa),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),s=u*c-i*a,l=i*o-r*c,f=r*a-u*o,h=Math.sqrt(s*s+l*l+f*f),g=r*o+u*a+i*c,p=h&&-J(g)/h,v=Math.atan2(h,g);Mc+=p*s,_c+=p*l,bc+=p*f,gc+=v,mc+=v*(r+(r=o)),yc+=v*(u+(u=a)),xc+=v*(i+(i=c)),xe(r,u,i)}var t,e,r,u,i;wc.point=function(o,a){t=o,e=a,wc.point=n,o*=Aa;var c=Math.cos(a*=Aa);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),xe(r,u,i)},wc.lineEnd=function(){n(t,e),wc.lineEnd=_e,wc.point=ye}}function we(){return!0}function Se(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(me(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return u.lineEnd(),void 0}var c=new Ee(e,n,null,!0),s=new Ee(e,null,c,!1);c.o=s,i.push(c),o.push(s),c=new Ee(r,n,null,!1),s=new Ee(r,null,c,!0),c.o=s,i.push(c),o.push(s)}}),o.sort(t),ke(i),ke(o),i.length){for(var a=0,c=e,s=o.length;s>a;++a)o[a].e=c=!c;for(var l,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;l=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,s=l.length;s>a;++a)u.point((f=l[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){l=g.p.z;for(var a=l.length-1;a>=0;--a)u.point((f=l[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,l=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ke(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function Ee(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Ae(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function s(){y.point=o,d.lineEnd()}function l(n,t){v.push([n,t]);var e=u(n,t);M.point(e[0],e[1])}function f(){M.lineStart(),v=[]}function h(){l(v[0][0],v[0][1]),M.lineEnd();var n,t=M.clean(),e=x.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(_||(i.polygonStart(),_=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Ce))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:s,polygonStart:function(){y.point=l,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=s,g=Zo.merge(g);var n=Le(m,p);g.length?(_||(i.polygonStart(),_=!0),Se(g,ze,n,e,i)):n&&(_||(i.polygonStart(),_=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),_&&(i.polygonEnd(),_=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},x=Ne(),M=t(x),_=!1;return y}}function Ce(n){return n.length>1}function Ne(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:v,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function ze(n,t){return((n=n.x)[0]<0?n[1]-Sa-ka:Sa-n[1])-((t=t.x)[0]<0?t[1]-Sa-ka:Sa-t[1])}function Le(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;lc.reset();for(var a=0,c=t.length;c>a;++a){var s=t[a],l=s.length;if(l)for(var f=s[0],h=f[0],g=f[1]/2+ba/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===l&&(d=0),n=s[d];var m=n[0],y=n[1]/2+ba/4,x=Math.sin(y),M=Math.cos(y),_=m-h,b=_>=0?1:-1,w=b*_,S=w>ba,k=p*x;if(lc.add(Math.atan2(k*b*Math.sin(w),v*M+k*Math.cos(w))),i+=S?_+b*wa:_,S^h>=e^m>=e){var E=he(le(f),le(n));ve(E);var A=he(u,E);ve(A);var C=(S^_>=0?-1:1)*G(A[2]);(r>C||r===C&&(E[0]||E[1]))&&(o+=S^_>=0?1:-1)}if(!d++)break;h=m,p=x,v=M,f=n}}return(-ka>i||ka>i&&0>lc)^1&o}function Te(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?ba:-ba,c=ua(i-e);ua(c-ba)<ka?(n.point(e,r=(r+o)/2>0?Sa:-Sa),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=ba&&(ua(e-u)<ka&&(e-=u*ka),ua(i-a)<ka&&(i-=a*ka),r=qe(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function qe(n,t,e,r){var u,i,o=Math.sin(n-e);return ua(o)>ka?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function Re(n,t,e,r){var u;if(null==n)u=e*Sa,r.point(-ba,u),r.point(0,u),r.point(ba,u),r.point(ba,0),r.point(ba,-u),r.point(0,-u),r.point(-ba,-u),r.point(-ba,0),r.point(-ba,u);else if(ua(n[0]-t[0])>ka){var i=n[0]<t[0]?ba:-ba;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function De(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,s,l;return{lineStart:function(){s=c=!1,l=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?ba:-ba),h):0;if(!e&&(s=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(me(e,g)||me(p,g))&&(p[0]+=ka,p[1]+=ka,v=t(p[0],p[1]))),v!==c)l=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(l=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&me(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return l|(s&&c)<<1}}}function r(n,t,e){var r=le(n),u=le(t),o=[1,0,0],a=he(r,u),c=fe(a,a),s=a[0],l=c-s*s;if(!l)return!e&&n;var f=i*c/l,h=-i*s/l,g=he(o,a),p=pe(o,f),v=pe(a,h);ge(p,v);var d=g,m=fe(p,d),y=fe(d,d),x=m*m-y*(fe(p,p)-1);if(!(0>x)){var M=Math.sqrt(x),_=pe(d,(-m-M)/y);if(ge(_,p),_=de(_),!e)return _;var b,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(b=w,w=S,S=b);var A=S-w,C=ua(A-ba)<ka,N=C||ka>A;if(!C&&k>E&&(b=k,k=E,E=b),N?C?k+E>0^_[1]<(ua(_[0]-w)<ka?k:E):k<=_[1]&&_[1]<=E:A>ba^(w<=_[0]&&_[0]<=S)){var z=pe(d,(-m+M)/y);return ge(z,p),[_,de(z)]}}}function u(t,e){var r=o?n:ba-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ua(i)>ka,c=sr(n,6*Aa);return Ae(t,e,c,o?[0,-n]:[-ba,n-ba])}function Pe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,s=o.y,l=a.x,f=a.y,h=0,g=1,p=l-c,v=f-s;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-s,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-s,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:s+h*v}),1>g&&(u.b={x:c+g*p,y:s+g*v}),u}}}}}}function Ue(n,t,e,r){function u(r,u){return ua(r[0]-n)<ka?u>0?0:3:ua(r[0]-e)<ka?u>0?2:1:ua(r[1]-t)<ka?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,s=a[0];c>o;++o)i=a[o],s[1]<=r?i[1]>r&&W(s,i,n)>0&&++t:i[1]<=r&&W(s,i,n)<0&&--t,s=i;return 0!==t}function s(i,a,c,s){var l=0,f=0;if(null==i||(l=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do s.point(0===l||3===l?n:e,l>1?r:t);while((l=(l+c+4)%4)!==f)}else s.point(a[0],a[1])}function l(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){l(n,t)&&a.point(n,t)}function h(){N.point=p,d&&d.push(m=[]),S=!0,w=!1,_=b=0/0}function g(){v&&(p(y,x),M&&w&&A.rejoin(),v.push(A.buffer())),N.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-kc,Math.min(kc,n)),t=Math.max(-kc,Math.min(kc,t));var e=l(n,t);if(d&&m.push([n,t]),S)y=n,x=t,M=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:_,y:b},b:{x:n,y:t}};C(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}_=n,b=t,w=e}var v,d,m,y,x,M,_,b,w,S,k,E=a,A=Ne(),C=Pe(n,t,e,r),N={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=Zo.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),s(null,null,1,a),a.lineEnd()),u&&Se(v,i,t,s,a),a.polygonEnd()),v=d=m=null}};return N}}function je(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function He(n){var t=0,e=ba/3,r=tr(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*ba/180,e=n[1]*ba/180):[180*(t/ba),180*(e/ba)]},u}function Fe(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,G((i-(n*n+e*e)*u*u)/(2*u))]},e}function Oe(){function n(n,t){Ac+=u*n-r*t,r=n,u=t}var t,e,r,u;Tc.point=function(i,o){Tc.point=n,t=r=i,e=u=o},Tc.lineEnd=function(){n(t,e)}}function Ye(n,t){Cc>n&&(Cc=n),n>zc&&(zc=n),Nc>t&&(Nc=t),t>Lc&&(Lc=t)}function Ie(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Ze(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Ze(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Ze(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Ve(n,t){pc+=n,vc+=t,++dc}function Xe(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);mc+=o*(t+n)/2,yc+=o*(e+r)/2,xc+=o,Ve(t=n,e=r)}var t,e;Rc.point=function(r,u){Rc.point=n,Ve(t=r,e=u)}}function $e(){Rc.point=Ve}function Be(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);mc+=o*(r+n)/2,yc+=o*(u+t)/2,xc+=o,o=u*n-r*t,Mc+=o*(r+n),_c+=o*(u+t),bc+=3*o,Ve(r=n,u=t)}var t,e,r,u;Rc.point=function(i,o){Rc.point=n,Ve(t=r=i,e=u=o)},Rc.lineEnd=function(){n(t,e)}}function We(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,wa)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:v};return a}function Je(n){function t(n){return(a?r:e)(n)}function e(t){return Qe(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){x=0/0,S.point=i,t.lineStart()}function i(e,r){var i=le([e,r]),o=n(e,r);u(x,M,y,_,b,w,x=o[0],M=o[1],y=e,_=i[0],b=i[1],w=i[2],a,t),t.point(x,M)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=s,S.lineEnd=l}function s(n,t){i(f=n,h=t),g=x,p=M,v=_,d=b,m=w,S.point=i}function l(){u(x,M,y,_,b,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,x,M,_,b,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,s,l,f,h,g,p,v,d,m){var y=l-t,x=f-e,M=y*y+x*x;if(M>4*i&&d--){var _=a+g,b=c+p,w=s+v,S=Math.sqrt(_*_+b*b+w*w),k=Math.asin(w/=S),E=ua(ua(w)-1)<ka||ua(r-h)<ka?(r+h)/2:Math.atan2(b,_),A=n(E,k),C=A[0],N=A[1],z=C-t,L=N-e,T=x*z-y*L;(T*T/M>i||ua((y*z+x*L)/M-.5)>.3||o>a*g+c*p+s*v)&&(u(t,e,r,a,c,s,C,N,E,_/=S,b/=S,w,d,m),m.point(C,N),u(C,N,E,_,b,w,l,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Aa),a=16; - return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function Ge(n){var t=Je(function(t,e){return n([t*Ca,e*Ca])});return function(n){return er(t(n))}}function Ke(n){this.stream=n}function Qe(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function nr(n){return tr(function(){return n})()}function tr(n){function t(n){return n=a(n[0]*Aa,n[1]*Aa),[n[0]*h+c,s-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(s-n[1])/h),n&&[n[0]*Ca,n[1]*Ca]}function r(){a=je(o=ir(m,y,x),i);var n=i(v,d);return c=g-n[0]*h,s=p+n[1]*h,u()}function u(){return l&&(l.valid=!1,l=null),t}var i,o,a,c,s,l,f=Je(function(n,t){return n=i(n,t),[n[0]*h+c,s-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,y=0,x=0,M=Sc,_=wt,b=null,w=null;return t.stream=function(n){return l&&(l.valid=!1),l=er(M(o,f(_(n)))),l.valid=!0,l},t.clipAngle=function(n){return arguments.length?(M=null==n?(b=n,Sc):De((b=+n)*Aa),u()):b},t.clipExtent=function(n){return arguments.length?(w=n,_=n?Ue(n[0][0],n[0][1],n[1][0],n[1][1]):wt,u()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Aa,d=n[1]%360*Aa,r()):[v*Ca,d*Ca]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Aa,y=n[1]%360*Aa,x=n.length>2?n[2]%360*Aa:0,r()):[m*Ca,y*Ca,x*Ca]},Zo.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function er(n){return Qe(n,function(t,e){n.point(t*Aa,e*Aa)})}function rr(n,t){return[n,t]}function ur(n,t){return[n>ba?n-wa:-ba>n?n+wa:n,t]}function ir(n,t,e){return n?t||e?je(ar(n),cr(t,e)):ar(n):t||e?cr(t,e):ur}function or(n){return function(t,e){return t+=n,[t>ba?t-wa:-ba>t?t+wa:t,e]}}function ar(n){var t=or(n);return t.invert=or(-n),t}function cr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*r+a*u;return[Math.atan2(c*i-l*o,a*r-s*u),G(l*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*i-c*o;return[Math.atan2(c*i+s*o,a*r+l*u),G(l*r-a*u)]},e}function sr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=lr(e,u),i=lr(e,i),(o>0?i>u:u>i)&&(u+=o*wa)):(u=n+o*wa,i=n-.5*c);for(var s,l=u;o>0?l>i:i>l;l-=c)a.point((s=de([e,-r*Math.cos(l),-r*Math.sin(l)]))[0],s[1])}}function lr(n,t){var e=le(t);e[0]-=n,ve(e);var r=J(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-ka)%(2*Math.PI)}function fr(n,t,e){var r=Zo.range(n,t-ka,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function hr(n,t,e){var r=Zo.range(n,t-ka,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function gr(n){return n.source}function pr(n){return n.target}function vr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),s=u*Math.sin(n),l=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(tt(r-t)+u*o*tt(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*l,u=e*s+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Ca,Math.atan2(o,Math.sqrt(r*r+u*u))*Ca]}:function(){return[n*Ca,t*Ca]};return p.distance=h,p}function dr(){function n(n,u){var i=Math.sin(u*=Aa),o=Math.cos(u),a=ua((n*=Aa)-t),c=Math.cos(a);Dc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Pc.point=function(u,i){t=u*Aa,e=Math.sin(i*=Aa),r=Math.cos(i),Pc.point=n},Pc.lineEnd=function(){Pc.point=Pc.lineEnd=v}}function mr(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function yr(n,t){function e(n,t){o>0?-Sa+ka>t&&(t=-Sa+ka):t>Sa-ka&&(t=Sa-ka);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(ba/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=B(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Sa]},e):Mr}function xr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ua(u)<ka?rr:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-B(u)*Math.sqrt(n*n+e*e)]},e)}function Mr(n,t){return[n,Math.log(Math.tan(ba/4+t/2))]}function _r(n){var t,e=nr(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=ba*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function br(n,t){return[Math.log(Math.tan(ba/4+t/2)),-n]}function wr(n){return n[0]}function Sr(n){return n[1]}function kr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&W(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function Er(n,t){return n[0]-t[0]||n[1]-t[1]}function Ar(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Cr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],s=e[1],l=t[1]-c,f=r[1]-s,h=(a*(c-s)-f*(u-i))/(f*o-a*l);return[u+h*o,c+h*l]}function Nr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function zr(){Gr(this),this.edge=this.site=this.circle=null}function Lr(n){var t=Bc.pop()||new zr;return t.site=n,t}function Tr(n){Yr(n),Vc.remove(n),Bc.push(n),Gr(n)}function qr(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Tr(n);for(var c=i;c.circle&&ua(e-c.circle.x)<ka&&ua(r-c.circle.cy)<ka;)i=c.P,a.unshift(c),Tr(c),c=i;a.unshift(c),Yr(c);for(var s=o;s.circle&&ua(e-s.circle.x)<ka&&ua(r-s.circle.cy)<ka;)o=s.N,a.push(s),Tr(s),s=o;a.push(s),Yr(s);var l,f=a.length;for(l=1;f>l;++l)s=a[l],c=a[l-1],Br(s.edge,c.site,s.site,u);c=a[0],s=a[f-1],s.edge=Xr(c.site,s.site,null,u),Or(c),Or(s)}function Rr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Vc._;a;)if(r=Dr(a,o)-i,r>ka)a=a.L;else{if(u=i-Pr(a,o),!(u>ka)){r>-ka?(t=a.P,e=a):u>-ka?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Lr(n);if(Vc.insert(t,c),t||e){if(t===e)return Yr(t),e=Lr(t.site),Vc.insert(c,e),c.edge=e.edge=Xr(t.site,c.site),Or(t),Or(e),void 0;if(!e)return c.edge=Xr(t.site,c.site),void 0;Yr(t),Yr(e);var s=t.site,l=s.x,f=s.y,h=n.x-l,g=n.y-f,p=e.site,v=p.x-l,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,x=v*v+d*d,M={x:(d*y-g*x)/m+l,y:(h*x-v*y)/m+f};Br(e.edge,s,p,M),c.edge=Xr(s,n,null,M),e.edge=Xr(n,p,null,M),Or(t),Or(e)}}function Dr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,s=c-t;if(!s)return a;var l=a-r,f=1/i-1/s,h=l/s;return f?(-h+Math.sqrt(h*h-2*f*(l*l/(-2*s)-c+s/2+u-i/2)))/f+r:(r+a)/2}function Pr(n,t){var e=n.N;if(e)return Dr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ur(n){this.site=n,this.edges=[]}function jr(n){for(var t,e,r,u,i,o,a,c,s,l,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Zc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)l=a[o].end(),r=l.x,u=l.y,s=a[++o%c].start(),t=s.x,e=s.y,(ua(r-t)>ka||ua(u-e)>ka)&&(a.splice(o,0,new Wr($r(i.site,l,ua(r-f)<ka&&p-u>ka?{x:f,y:ua(t-f)<ka?e:p}:ua(u-p)<ka&&h-r>ka?{x:ua(e-p)<ka?t:h,y:p}:ua(r-h)<ka&&u-g>ka?{x:h,y:ua(t-h)<ka?e:g}:ua(u-g)<ka&&r-f>ka?{x:ua(e-g)<ka?t:f,y:g}:null),i.site,null)),++c)}function Hr(n,t){return t.angle-n.angle}function Fr(){Gr(this),this.x=this.y=this.arc=this.site=this.cy=null}function Or(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,s=r.y-a,l=i.x-o,f=i.y-a,h=2*(c*f-s*l);if(!(h>=-Ea)){var g=c*c+s*s,p=l*l+f*f,v=(f*g-s*p)/h,d=(c*p-l*g)/h,f=d+a,m=Wc.pop()||new Fr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,x=$c._;x;)if(m.y<x.y||m.y===x.y&&m.x<=x.x){if(!x.L){y=x.P;break}x=x.L}else{if(!x.R){y=x;break}x=x.R}$c.insert(y,m),y||(Xc=m)}}}}function Yr(n){var t=n.circle;t&&(t.P||(Xc=t.N),$c.remove(t),Wc.push(t),Gr(t),n.circle=null)}function Ir(n){for(var t,e=Ic,r=Pe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Zr(t,n)||!r(t)||ua(t.a.x-t.b.x)<ka&&ua(t.a.y-t.b.y)<ka)&&(t.a=t.b=null,e.splice(u,1))}function Zr(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],s=t[1][1],l=n.l,f=n.r,h=l.x,g=l.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=s)return}else i={x:d,y:c};e={x:d,y:s}}else{if(i){if(i.y<c)return}else i={x:d,y:s};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=s)return}else i={x:(c-u)/r,y:c};e={x:(s-u)/r,y:s}}else{if(i){if(i.y<c)return}else i={x:(s-u)/r,y:s};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Vr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Xr(n,t,e,r){var u=new Vr(n,t);return Ic.push(u),e&&Br(u,n,t,e),r&&Br(u,t,n,r),Zc[n.i].edges.push(new Wr(u,n,t)),Zc[t.i].edges.push(new Wr(u,t,n)),u}function $r(n,t,e){var r=new Vr(n,null);return r.a=t,r.b=e,Ic.push(r),r}function Br(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Wr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function Jr(){this._=null}function Gr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function Kr(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Qr(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function nu(n){for(;n.L;)n=n.L;return n}function tu(n,t){var e,r,u,i=n.sort(eu).pop();for(Ic=[],Zc=new Array(n.length),Vc=new Jr,$c=new Jr;;)if(u=Xc,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Zc[i.i]=new Ur(i),Rr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;qr(u.arc)}t&&(Ir(t),jr(t));var o={cells:Zc,edges:Ic};return Vc=$c=Ic=Zc=null,o}function eu(n,t){return t.y-n.y||t.x-n.x}function ru(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function uu(n){return n.x}function iu(n){return n.y}function ou(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function au(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&au(n,c[0],e,r,o,a),c[1]&&au(n,c[1],o,r,u,a),c[2]&&au(n,c[2],e,a,o,i),c[3]&&au(n,c[3],o,a,u,i)}}function cu(n,t){n=Zo.rgb(n),t=Zo.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+dt(Math.round(e+i*n))+dt(Math.round(r+o*n))+dt(Math.round(u+a*n))}}function su(n,t){var e,r={},u={};for(e in n)e in t?r[e]=hu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function lu(n,t){return t-=n=+n,function(e){return n+t*e}}function fu(n,t){var e,r,u,i=Gc.lastIndex=Kc.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=Gc.exec(n))&&(r=Kc.exec(t));)(u=r.index)>i&&(u=t.substring(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:lu(e,r)})),i=Kc.lastIndex;return i<t.length&&(u=t.substring(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function hu(n,t){for(var e,r=Zo.interpolators.length;--r>=0&&!(e=Zo.interpolators[r](n,t)););return e}function gu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(hu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function pu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function vu(n){return function(t){return 1-n(1-t)}}function du(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function mu(n){return n*n}function yu(n){return n*n*n}function xu(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Mu(n){return function(t){return Math.pow(t,n)}}function _u(n){return 1-Math.cos(n*Sa)}function bu(n){return Math.pow(2,10*(n-1))}function wu(n){return 1-Math.sqrt(1-n*n)}function Su(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/wa*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*wa/t)}}function ku(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Eu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Au(n,t){n=Zo.hcl(n),t=Zo.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ot(e+i*n,r+o*n,u+a*n)+""}}function Cu(n,t){n=Zo.hsl(n),t=Zo.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ut(e+i*n,r+o*n,u+a*n)+""}}function Nu(n,t){n=Zo.lab(n),t=Zo.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function zu(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Lu(n){var t=[n.a,n.b],e=[n.c,n.d],r=qu(t),u=Tu(t,e),i=qu(Ru(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Ca,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Ca:0}function Tu(n,t){return n[0]*t[0]+n[1]*t[1]}function qu(n){var t=Math.sqrt(Tu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Ru(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Du(n,t){var e,r=[],u=[],i=Zo.transform(n),o=Zo.transform(t),a=i.translate,c=o.translate,s=i.rotate,l=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:lu(a[0],c[0])},{i:3,x:lu(a[1],c[1])})):c[0]||c[1]?r.push("translate("+c+")"):r.push(""),s!=l?(s-l>180?l+=360:l-s>180&&(s+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:lu(s,l)})):l&&r.push(r.pop()+"rotate("+l+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:lu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:lu(g[0],p[0])},{i:e-2,x:lu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Pu(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return(e-n)*t}}function Uu(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return Math.max(0,Math.min(1,(e-n)*t))}}function ju(n){for(var t=n.source,e=n.target,r=Fu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Hu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Fu(n,t){if(n===t)return n;for(var e=Hu(n),r=Hu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Ou(n){n.fixed|=2}function Yu(n){n.fixed&=-7}function Iu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Zu(n){n.fixed&=-5}function Vu(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Vu(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var s=t*e[n.point.index];n.charge+=n.pointCharge=s,r+=s*n.point.x,u+=s*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Xu(n,t){return Zo.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=Ku,n}function $u(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Bu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function Wu(n){return n.children}function Ju(n){return n.value}function Gu(n,t){return t.value-n.value}function Ku(n){return Zo.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function Qu(n){return n.x}function ni(n){return n.y}function ti(n,t,e){n.y0=t,n.y=e}function ei(n){return Zo.range(n.length)}function ri(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function ui(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function ii(n){return n.reduce(oi,0)}function oi(n,t){return n+t[1]}function ai(n,t){return ci(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function ci(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function si(n){return[Zo.min(n),Zo.max(n)]}function li(n,t){return n.value-t.value}function fi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function hi(n,t){n._pack_next=t,t._pack_prev=n}function gi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function pi(n){function t(n){l=Math.min(n.x-n.r,l),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(s=e.length)){var e,r,u,i,o,a,c,s,l=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(vi),r=e[0],r.x=-r.r,r.y=0,t(r),s>1&&(u=e[1],u.x=u.r,u.y=0,t(u),s>2))for(i=e[2],yi(r,u,i),t(i),fi(r,i),r._pack_prev=i,fi(i,u),u=r._pack_next,o=3;s>o;o++){yi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(gi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!gi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?hi(r,u=a):hi(r=c,u),o--):(fi(r,i),u=i,t(i))}var m=(l+f)/2,y=(h+g)/2,x=0;for(o=0;s>o;o++)i=e[o],i.x-=m,i.y-=y,x=Math.max(x,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=x,e.forEach(di)}}function vi(n){n._pack_next=n._pack_prev=n}function di(n){delete n._pack_next,delete n._pack_prev}function mi(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)mi(u[i],t,e,r)}function yi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),s=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+s*i,e.y=n.y+c*i-s*u}else e.x=n.x+r,e.y=n.y}function xi(n,t){return n.parent==t.parent?1:2}function Mi(n){var t=n.children;return t.length?t[0]:n.t}function _i(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function bi(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function wi(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Si(n,t,e){return n.a.parent===t.parent?n.a:e}function ki(n){return 1+Zo.max(n,function(n){return n.y})}function Ei(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Ai(n){var t=n.children;return t&&t.length?Ai(t[0]):n}function Ci(n){var t,e=n.children;return e&&(t=e.length)?Ci(e[t-1]):n}function Ni(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function zi(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Li(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ti(n){return n.rangeExtent?n.rangeExtent():Li(n.range())}function qi(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Ri(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Di(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ss}function Pi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=Zo.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ui(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Pi:qi,c=r?Uu:Pu;return o=u(n,t,c,e),a=u(t,n,c,hu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(zu)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Oi(n,t)},i.tickFormat=function(t,e){return Yi(n,t,e)},i.nice=function(t){return Hi(n,t),u()},i.copy=function(){return Ui(n,t,e,r)},u()}function ji(n,t){return Zo.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Hi(n,t){return Ri(n,Di(Fi(n,t)[2]))}function Fi(n,t){null==t&&(t=10);var e=Li(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Oi(n,t){return Zo.range.apply(Zo,Fi(n,t))}function Yi(n,t,e){var r=Fi(n,t);if(e){var u=Ga.exec(e);if(u.shift(),"s"===u[8]){var i=Zo.formatPrefix(Math.max(ua(r[0]),ua(r[1])));return u[7]||(u[7]="."+Ii(i.scale(r[2]))),u[8]="f",e=Zo.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Zi(u[8],r)),e=u.join("")}else e=",."+Ii(r[2])+"f";return Zo.format(e)}function Ii(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Zi(n,t){var e=Ii(t[2]);return n in ls?Math.abs(e-Ii(Math.max(ua(t[0]),ua(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Vi(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Ri(r.map(u),e?Math:hs);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Li(r),o=[],a=n[0],c=n[1],s=Math.floor(u(a)),l=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(l-s)){if(e){for(;l>s;s++)for(var h=1;f>h;h++)o.push(i(s)*h);o.push(i(s))}else for(o.push(i(s));s++<l;)for(var h=f-1;h>0;h--)o.push(i(s)*h);for(s=0;o[s]<a;s++);for(l=o.length;o[l-1]>c;l--);o=o.slice(s,l)}return o},o.tickFormat=function(n,t){if(!arguments.length)return fs;arguments.length<2?t=fs:"function"!=typeof t&&(t=Zo.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Vi(n.copy(),t,e,r)},ji(o,n)}function Xi(n,t,e){function r(t){return n(u(t))}var u=$i(t),i=$i(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Oi(e,n)},r.tickFormat=function(n,t){return Yi(e,n,t)},r.nice=function(n){return r.domain(Hi(e,n))},r.exponent=function(o){return arguments.length?(u=$i(t=o),i=$i(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Xi(n.copy(),t,e)},ji(r,n)}function $i(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Bi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return Zo.range(n.length).map(function(n){return t+e*n})}var u,i,a;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new o;for(var i,a=-1,c=r.length;++a<c;)u.has(i=r[a])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,a=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,o){arguments.length<2&&(o=0);var c=u[0],s=u[1],l=(s-c)/(Math.max(1,n.length-1)+o);return i=r(n.length<2?(c+s)/2:c+l*o/2,l),a=0,t={t:"rangePoints",a:arguments},e},e.rangeBands=function(u,o,c){arguments.length<2&&(o=0),arguments.length<3&&(c=o);var s=u[1]<u[0],l=u[s-0],f=u[1-s],h=(f-l)/(n.length-o+2*c);return i=r(l+h*c,h),s&&i.reverse(),a=h*(1-o),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,o,c){arguments.length<2&&(o=0),arguments.length<3&&(c=o);var s=u[1]<u[0],l=u[s-0],f=u[1-s],h=Math.floor((f-l)/(n.length-o+2*c)),g=f-l-(n.length-o)*h;return i=r(l+Math.round(g/2),h),s&&i.reverse(),a=Math.round(h*(1-o)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return a},e.rangeExtent=function(){return Li(t.a[0])},e.copy=function(){return Bi(n,t)},e.domain(n)}function Wi(e,r){function u(){var n=0,t=r.length;for(o=[];++n<t;)o[n-1]=Zo.quantile(e,n/t);return i}function i(n){return isNaN(n=+n)?void 0:r[Zo.bisect(o,n)]}var o;return i.domain=function(r){return arguments.length?(e=r.filter(t).sort(n),u()):e},i.range=function(n){return arguments.length?(r=n,u()):r},i.quantiles=function(){return o},i.invertExtent=function(n){return n=r.indexOf(n),0>n?[0/0,0/0]:[n>0?o[n-1]:e[0],n<o.length?o[n]:e[e.length-1]]},i.copy=function(){return Wi(e,r)},u()}function Ji(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return Ji(n,t,e)},u()}function Gi(n,t){function e(e){return e>=e?t[Zo.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return Gi(n,t)},e}function Ki(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Oi(n,t)},t.tickFormat=function(t,e){return Yi(n,t,e)},t.copy=function(){return Ki(n)},t}function Qi(n){return n.innerRadius}function no(n){return n.outerRadius}function to(n){return n.startAngle}function eo(n){return n.endAngle}function ro(n){function t(t){function o(){s.push("M",i(n(l),a))}for(var c,s=[],l=[],f=-1,h=t.length,g=bt(e),p=bt(r);++f<h;)u.call(this,c=t[f],f)?l.push([+g.call(this,c,f),+p.call(this,c,f)]):l.length&&(o(),l=[]);return l.length&&o(),s.length?s.join(""):null}var e=wr,r=Sr,u=we,i=uo,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=xs.get(n)||uo).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function uo(n){return n.join("L")}function io(n){return uo(n)+"Z"}function oo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function ao(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function co(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function so(n,t){return n.length<4?uo(n):n[1]+ho(n.slice(1,n.length-1),go(n,t))}function lo(n,t){return n.length<3?uo(n):n[0]+ho((n.push(n[0]),n),go([n[n.length-2]].concat(n,[n[1]]),t))}function fo(n,t){return n.length<3?uo(n):n[0]+ho(n,go(n,t))}function ho(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return uo(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var s=2;s<t.length;s++,c++)i=n[c],a=t[s],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var l=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+l[0]+","+l[1]}return r}function go(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function po(n){if(n.length<3)return uo(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",xo(bs,o),",",xo(bs,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Mo(c,o,a);return n.pop(),c.push("L",r),c.join("")}function vo(n){if(n.length<4)return uo(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(xo(bs,i)+","+xo(bs,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Mo(e,i,o);return e.join("")}function mo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[xo(bs,o),",",xo(bs,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Mo(t,o,a);return t.join("")}function yo(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,s=-1;++s<=e;)r=n[s],u=s/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return po(n)}function xo(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Mo(n,t,e){n.push("C",xo(Ms,t),",",xo(Ms,e),",",xo(_s,t),",",xo(_s,e),",",xo(bs,t),",",xo(bs,e))}function _o(n,t){return(t[1]-n[1])/(t[0]-n[0])}function bo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=_o(u,i);++t<e;)r[t]=(o+(o=_o(u=i,i=n[t+1])))/2;return r[t]=o,r}function wo(n){for(var t,e,r,u,i=[],o=bo(n),a=-1,c=n.length-1;++a<c;)t=_o(n[a],n[a+1]),ua(t)<ka?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function So(n){return n.length<3?uo(n):n[0]+ho(n,wo(n))}function ko(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]+ms,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Eo(n){function t(t){function c(){v.push("M",a(n(m),f),l,s(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,x=t.length,M=bt(e),_=bt(u),b=e===r?function(){return g}:bt(r),w=u===i?function(){return p}:bt(i);++y<x;)o.call(this,h=t[y],y)?(d.push([g=+M.call(this,h,y),p=+_.call(this,h,y)]),m.push([+b.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=wr,r=wr,u=0,i=Sr,o=we,a=uo,c=a.key,s=a,l="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=xs.get(n)||uo).key,s=a.reverse||a,l=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Ao(n){return n.radius}function Co(n){return[n.x,n.y]}function No(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]+ms;return[e*Math.cos(r),e*Math.sin(r)]}}function zo(){return 64}function Lo(){return"circle"}function To(n){var t=Math.sqrt(n/ba);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function qo(n,t){return sa(n,Cs),n.id=t,n}function Ro(n,t,e,r){var u=n.id;return P(n,"function"==typeof e?function(n,i,o){n.__transition__[u].tween.set(t,r(e.call(n,n.__data__,i,o)))}:(e=r(e),function(n){n.__transition__[u].tween.set(t,e)}))}function Do(n){return null==n&&(n=""),function(){this.textContent=n}}function Po(n,t,e,r){var u=n.__transition__||(n.__transition__={active:0,count:0}),i=u[e];if(!i){var a=r.time;i=u[e]={tween:new o,time:a,ease:r.ease,delay:r.delay,duration:r.duration},++u.count,Zo.timer(function(r){function o(r){return u.active>e?s():(u.active=e,i.event&&i.event.start.call(n,l,t),i.tween.forEach(function(e,r){(r=r.call(n,l,t))&&v.push(r)}),Zo.timer(function(){return p.c=c(r||1)?we:c,1},0,a),void 0)}function c(r){if(u.active!==e)return s();for(var o=r/g,a=f(o),c=v.length;c>0;)v[--c].call(n,a); - return o>=1?(i.event&&i.event.end.call(n,l,t),s()):void 0}function s(){return--u.count?delete u[e]:delete n.__transition__,1}var l=n.__data__,f=i.ease,h=i.delay,g=i.duration,p=Ba,v=[];return p.t=h+a,r>=h?o(r-h):(p.c=o,void 0)},0,a)}}function Uo(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}function jo(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function Ho(n){return n.toISOString()}function Fo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=Zo.bisect(Us,u);return i==Us.length?[t.year,Fi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Us[i-1]<Us[i]/u?i-1:i]:[Fs,Fi(n,e)[2]]}return r.invert=function(t){return Oo(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Oo)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Oo(+e+1),t).length}var i=r.domain(),o=Li(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Ri(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Oo(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Oo(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Li(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Oo(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Fo(n.copy(),t,e)},ji(r,n)}function Oo(n){return new Date(n)}function Yo(n){return JSON.parse(n.responseText)}function Io(n){var t=$o.createRange();return t.selectNode($o.body),t.createContextualFragment(n.responseText)}var Zo={version:"3.4.11"};Date.now||(Date.now=function(){return+new Date});var Vo=[].slice,Xo=function(n){return Vo.call(n)},$o=document,Bo=$o.documentElement,Wo=window;try{Xo(Bo.childNodes)[0].nodeType}catch(Jo){Xo=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}try{$o.createElement("div").style.setProperty("opacity",0,"")}catch(Go){var Ko=Wo.Element.prototype,Qo=Ko.setAttribute,na=Ko.setAttributeNS,ta=Wo.CSSStyleDeclaration.prototype,ea=ta.setProperty;Ko.setAttribute=function(n,t){Qo.call(this,n,t+"")},Ko.setAttributeNS=function(n,t,e){na.call(this,n,t,e+"")},ta.setProperty=function(n,t,e){ea.call(this,n,t+"",e)}}Zo.ascending=n,Zo.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},Zo.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},Zo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},Zo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o&&!(null!=(e=u=n[i])&&e>=e);)e=u=void 0;for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o&&!(null!=(e=u=t.call(n,n[i],i))&&e>=e);)e=void 0;for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},Zo.sum=function(n,t){var e,r=0,u=n.length,i=-1;if(1===arguments.length)for(;++i<u;)isNaN(e=+n[i])||(r+=e);else for(;++i<u;)isNaN(e=+t.call(n,n[i],i))||(r+=e);return r},Zo.mean=function(n,e){var r,u=0,i=n.length,o=-1,a=i;if(1===arguments.length)for(;++o<i;)t(r=n[o])?u+=r:--a;else for(;++o<i;)t(r=e.call(n,n[o],o))?u+=r:--a;return a?u/a:void 0},Zo.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},Zo.median=function(e,r){return arguments.length>1&&(e=e.map(r)),e=e.filter(t),e.length?Zo.quantile(e.sort(n),.5):void 0};var ra=e(n);Zo.bisectLeft=ra.left,Zo.bisect=Zo.bisectRight=ra.right,Zo.bisector=function(t){return e(1===t.length?function(e,r){return n(t(e),r)}:t)},Zo.shuffle=function(n){for(var t,e,r=n.length;r;)e=0|Math.random()*r--,t=n[r],n[r]=n[e],n[e]=t;return n},Zo.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},Zo.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},Zo.zip=function(){if(!(u=arguments.length))return[];for(var n=-1,t=Zo.min(arguments,r),e=new Array(t);++n<t;)for(var u,i=-1,o=e[n]=new Array(u);++i<u;)o[i]=arguments[i][n];return e},Zo.transpose=function(n){return Zo.zip.apply(Zo,n)},Zo.keys=function(n){var t=[];for(var e in n)t.push(e);return t},Zo.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},Zo.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},Zo.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ua=Math.abs;Zo.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/e)throw new Error("infinite range");var r,i=[],o=u(ua(e)),a=-1;if(n*=o,t*=o,e*=o,0>e)for(;(r=n+e*++a)>t;)i.push(r/o);else for(;(r=n+e*++a)<t;)i.push(r/o);return i},Zo.map=function(n){var t=new o;if(n instanceof o)n.forEach(function(n,e){t.set(n,e)});else for(var e in n)t.set(e,n[e]);return t},i(o,{has:a,get:function(n){return this[ia+n]},set:function(n,t){return this[ia+n]=t},remove:c,keys:s,values:function(){var n=[];return this.forEach(function(t,e){n.push(e)}),n},entries:function(){var n=[];return this.forEach(function(t,e){n.push({key:t,value:e})}),n},size:l,empty:f,forEach:function(n){for(var t in this)t.charCodeAt(0)===oa&&n.call(this,t.substring(1),this[t])}});var ia="\x00",oa=ia.charCodeAt(0);Zo.nest=function(){function n(t,a,c){if(c>=i.length)return r?r.call(u,a):e?a.sort(e):a;for(var s,l,f,h,g=-1,p=a.length,v=i[c++],d=new o;++g<p;)(h=d.get(s=v(l=a[g])))?h.push(l):d.set(s,[l]);return t?(l=t(),f=function(e,r){l.set(e,n(t,r,c))}):(l={},f=function(e,r){l[e]=n(t,r,c)}),d.forEach(f),l}function t(n,e){if(e>=i.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],a=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(Zo.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return a[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},Zo.set=function(n){var t=new h;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},i(h,{has:a,add:function(n){return this[ia+n]=!0,n},remove:function(n){return n=ia+n,n in this&&delete this[n]},values:s,size:l,empty:f,forEach:function(n){for(var t in this)t.charCodeAt(0)===oa&&n.call(this,t.substring(1))}}),Zo.behavior={},Zo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=g(n,t,t[e]);return n};var aa=["webkit","ms","moz","Moz","o","O"];Zo.dispatch=function(){for(var n=new d,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=m(n);return n},d.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},Zo.event=null,Zo.requote=function(n){return n.replace(ca,"\\$&")};var ca=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,sa={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},la=function(n,t){return t.querySelector(n)},fa=function(n,t){return t.querySelectorAll(n)},ha=Bo.matches||Bo[p(Bo,"matchesSelector")],ga=function(n,t){return ha.call(n,t)};"function"==typeof Sizzle&&(la=function(n,t){return Sizzle(n,t)[0]||null},fa=Sizzle,ga=Sizzle.matchesSelector),Zo.selection=function(){return ma};var pa=Zo.selection.prototype=[];pa.select=function(n){var t,e,r,u,i=[];n=b(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,s=r.length;++c<s;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return _(i)},pa.selectAll=function(n){var t,e,r=[];n=w(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=Xo(n.call(e,e.__data__,a,u))),t.parentNode=e);return _(r)};var va={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};Zo.ns={prefix:va,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.substring(0,t),n=n.substring(t+1)),va.hasOwnProperty(e)?{space:va[e],local:n}:n}},pa.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=Zo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(S(t,n[t]));return this}return this.each(S(n,t))},pa.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=A(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!E(n[u]).test(t))return!1;return!0}for(t in n)this.each(C(t,n[t]));return this}return this.each(C(n,t))},pa.style=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t="");for(e in n)this.each(z(e,n[e],t));return this}if(2>r)return Wo.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return this.each(z(n,t,e))},pa.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(L(t,n[t]));return this}return this.each(L(n,t))},pa.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},pa.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},pa.append=function(n){return n=T(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},pa.insert=function(n,t){return n=T(n),t=b(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},pa.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},pa.data=function(n,t){function e(n,e){var r,u,i,a=n.length,f=e.length,h=Math.min(a,f),g=new Array(f),p=new Array(f),v=new Array(a);if(t){var d,m=new o,y=new o,x=[];for(r=-1;++r<a;)d=t.call(u=n[r],u.__data__,r),m.has(d)?v[r]=u:m.set(d,u),x.push(d);for(r=-1;++r<f;)d=t.call(e,i=e[r],r),(u=m.get(d))?(g[r]=u,u.__data__=i):y.has(d)||(p[r]=q(i)),y.set(d,i),m.remove(d);for(r=-1;++r<a;)m.has(x[r])&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=q(i);for(;f>r;++r)p[r]=q(e[r]);for(;a>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,c.push(p),s.push(g),l.push(v)}var r,u,i=-1,a=this.length;if(!arguments.length){for(n=new Array(a=(r=this[0]).length);++i<a;)(u=r[i])&&(n[i]=u.__data__);return n}var c=U([]),s=_([]),l=_([]);if("function"==typeof n)for(;++i<a;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<a;)e(r=this[i],n);return s.enter=function(){return c},s.exit=function(){return l},s},pa.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},pa.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=R(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return _(u)},pa.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},pa.sort=function(n){n=D.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},pa.each=function(n){return P(this,function(t,e,r){n.call(t,t.__data__,e,r)})},pa.call=function(n){var t=Xo(arguments);return n.apply(t[0]=this,t),this},pa.empty=function(){return!this.node()},pa.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},pa.size=function(){var n=0;return this.each(function(){++n}),n};var da=[];Zo.selection.enter=U,Zo.selection.enter.prototype=da,da.append=pa.append,da.empty=pa.empty,da.node=pa.node,da.call=pa.call,da.size=pa.size,da.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var s=-1,l=u.length;++s<l;)(i=u[s])?(t.push(r[s]=e=n.call(u.parentNode,i.__data__,s,a)),e.__data__=i.__data__):t.push(null)}return _(o)},da.insert=function(n,t){return arguments.length<2&&(t=j(this)),pa.insert.call(this,n,t)},pa.transition=function(){for(var n,t,e=Ss||++Ns,r=[],u=ks||{time:Date.now(),ease:xu,delay:0,duration:250},i=-1,o=this.length;++i<o;){r.push(n=[]);for(var a=this[i],c=-1,s=a.length;++c<s;)(t=a[c])&&Po(t,c,e,u),n.push(t)}return qo(r,e)},pa.interrupt=function(){return this.each(H)},Zo.select=function(n){var t=["string"==typeof n?la(n,$o):n];return t.parentNode=Bo,_([t])},Zo.selectAll=function(n){var t=Xo("string"==typeof n?fa(n,$o):n);return t.parentNode=Bo,_([t])};var ma=Zo.select(Bo);pa.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(F(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(F(n,t,e))};var ya=Zo.map({mouseenter:"mouseover",mouseleave:"mouseout"});ya.forEach(function(n){"on"+n in $o&&ya.remove(n)});var xa="onselectstart"in $o?null:p(Bo.style,"userSelect"),Ma=0;Zo.mouse=function(n){return Z(n,x())};var _a=/WebKit/.test(Wo.navigator.userAgent)?-1:0;Zo.touches=function(n,t){return arguments.length<2&&(t=x().touches),t?Xo(t).map(function(t){var e=Z(n,t);return e.identifier=t.identifier,e}):[]},Zo.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",i)}function t(n,t,u,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-x[0],e=r[1]-x[1],p|=n|e,x=r,g({type:"drag",x:r[0]+s[0],y:r[1]+s[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&Zo.event.target===f),g({type:"dragend"}))}var s,l=this,f=Zo.event.target,h=l.parentNode,g=e.of(l,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=Zo.select(u()).on(i+d,a).on(o+d,c),y=I(),x=t(h,v);r?(s=r.apply(l,arguments),s=[s.x-x[0],s.y-x[1]]):s=[0,0],g({type:"dragstart"})}}var e=M(n,"drag","dragstart","dragend"),r=null,u=t(v,Zo.mouse,$,"mousemove","mouseup"),i=t(V,Zo.touch,X,"touchmove","touchend");return n.origin=function(t){return arguments.length?(r=t,n):r},Zo.rebind(n,e,"on")};var ba=Math.PI,wa=2*ba,Sa=ba/2,ka=1e-6,Ea=ka*ka,Aa=ba/180,Ca=180/ba,Na=Math.SQRT2,za=2,La=4;Zo.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=Q(v),o=i/(za*h)*(e*nt(Na*t+v)-K(v));return[r+o*s,u+o*l,i*e/Q(Na*t+v)]}return[r+n*s,u+n*l,i*Math.exp(Na*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],s=o-r,l=a-u,f=s*s+l*l,h=Math.sqrt(f),g=(c*c-i*i+La*f)/(2*i*za*h),p=(c*c-i*i-La*f)/(2*c*za*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Na;return e.duration=1e3*y,e},Zo.behavior.zoom=function(){function n(n){n.on(A,s).on(Ra+".zoom",f).on("dblclick.zoom",h).on(z,l)}function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}function r(n){S.k=Math.max(E[0],Math.min(E[1],n))}function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}function i(){_&&_.domain(x.range().map(function(n){return(n-S.x)/S.k}).map(x.invert)),w&&w.domain(b.range().map(function(n){return(n-S.y)/S.k}).map(b.invert))}function o(n){n({type:"zoomstart"})}function a(n){i(),n({type:"zoom",scale:S.k,translate:[S.x,S.y]})}function c(n){n({type:"zoomend"})}function s(){function n(){l=1,u(Zo.mouse(r),h),a(s)}function e(){f.on(C,null).on(N,null),g(l&&Zo.event.target===i),c(s)}var r=this,i=Zo.event.target,s=L.of(r,arguments),l=0,f=Zo.select(Wo).on(C,n).on(N,e),h=t(Zo.mouse(r)),g=I();H.call(r),o(s)}function l(){function n(){var n=Zo.touches(g);return h=S.k,n.forEach(function(n){n.identifier in v&&(v[n.identifier]=t(n))}),n}function e(){var t=Zo.event.target;Zo.select(t).on(M,i).on(_,f),b.push(t);for(var e=Zo.event.changedTouches,o=0,c=e.length;c>o;++o)v[e[o].identifier]=null;var s=n(),l=Date.now();if(1===s.length){if(500>l-m){var h=s[0],g=v[h.identifier];r(2*S.k),u(h,g),y(),a(p)}m=l}else if(s.length>1){var h=s[0],x=s[1],w=h[0]-x[0],k=h[1]-x[1];d=w*w+k*k}}function i(){for(var n,t,e,i,o=Zo.touches(g),c=0,s=o.length;s>c;++c,i=null)if(e=o[c],i=v[e.identifier]){if(t)break;n=e,t=i}if(i){var l=(l=e[0]-n[0])*l+(l=e[1]-n[1])*l,f=d&&Math.sqrt(l/d);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*h)}m=null,u(n,t),a(p)}function f(){if(Zo.event.touches.length){for(var t=Zo.event.changedTouches,e=0,r=t.length;r>e;++e)delete v[t[e].identifier];for(var u in v)return void n()}Zo.selectAll(b).on(x,null),w.on(A,s).on(z,l),k(),c(p)}var h,g=this,p=L.of(g,arguments),v={},d=0,x=".zoom-"+Zo.event.changedTouches[0].identifier,M="touchmove"+x,_="touchend"+x,b=[],w=Zo.select(g).on(A,null).on(z,e),k=I();H.call(g),e(),o(p)}function f(){var n=L.of(this,arguments);d?clearTimeout(d):(g=t(p=v||Zo.mouse(this)),H.call(this),o(n)),d=setTimeout(function(){d=null,c(n)},50),y(),r(Math.pow(2,.002*Ta())*S.k),u(p,g),a(n)}function h(){var n=L.of(this,arguments),e=Zo.mouse(this),i=t(e),s=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,Zo.event.shiftKey?Math.ceil(s)-1:Math.floor(s)+1)),u(e,i),a(n),c(n)}var g,p,v,d,m,x,_,b,w,S={x:0,y:0,k:1},k=[960,500],E=qa,A="mousedown.zoom",C="mousemove.zoom",N="mouseup.zoom",z="touchstart.zoom",L=M(n,"zoomstart","zoom","zoomend");return n.event=function(n){n.each(function(){var n=L.of(this,arguments),t=S;Ss?Zo.select(this).transition().each("start.zoom",function(){S=this.__chart__||{x:0,y:0,k:1},o(n)}).tween("zoom:zoom",function(){var e=k[0],r=k[1],u=e/2,i=r/2,o=Zo.interpolateZoom([(u-S.x)/S.k,(i-S.y)/S.k,e/S.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),c=e/r[2];this.__chart__=S={x:u-r[0]*c,y:i-r[1]*c,k:c},a(n)}}).each("end.zoom",function(){c(n)}):(this.__chart__=S,o(n),a(n),c(n))})},n.translate=function(t){return arguments.length?(S={x:+t[0],y:+t[1],k:S.k},i(),n):[S.x,S.y]},n.scale=function(t){return arguments.length?(S={x:S.x,y:S.y,k:+t},i(),n):S.k},n.scaleExtent=function(t){return arguments.length?(E=null==t?qa:[+t[0],+t[1]],n):E},n.center=function(t){return arguments.length?(v=t&&[+t[0],+t[1]],n):v},n.size=function(t){return arguments.length?(k=t&&[+t[0],+t[1]],n):k},n.x=function(t){return arguments.length?(_=t,x=t.copy(),S={x:0,y:0,k:1},n):_},n.y=function(t){return arguments.length?(w=t,b=t.copy(),S={x:0,y:0,k:1},n):w},Zo.rebind(n,L,"on")};var Ta,qa=[0,1/0],Ra="onwheel"in $o?(Ta=function(){return-Zo.event.deltaY*(Zo.event.deltaMode?120:1)},"wheel"):"onmousewheel"in $o?(Ta=function(){return Zo.event.wheelDelta},"mousewheel"):(Ta=function(){return-Zo.event.detail},"MozMousePixelScroll");Zo.color=et,et.prototype.toString=function(){return this.rgb()+""},Zo.hsl=rt;var Da=rt.prototype=new et;Da.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new rt(this.h,this.s,this.l/n)},Da.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new rt(this.h,this.s,n*this.l)},Da.rgb=function(){return ut(this.h,this.s,this.l)},Zo.hcl=it;var Pa=it.prototype=new et;Pa.brighter=function(n){return new it(this.h,this.c,Math.min(100,this.l+Ua*(arguments.length?n:1)))},Pa.darker=function(n){return new it(this.h,this.c,Math.max(0,this.l-Ua*(arguments.length?n:1)))},Pa.rgb=function(){return ot(this.h,this.c,this.l).rgb()},Zo.lab=at;var Ua=18,ja=.95047,Ha=1,Fa=1.08883,Oa=at.prototype=new et;Oa.brighter=function(n){return new at(Math.min(100,this.l+Ua*(arguments.length?n:1)),this.a,this.b)},Oa.darker=function(n){return new at(Math.max(0,this.l-Ua*(arguments.length?n:1)),this.a,this.b)},Oa.rgb=function(){return ct(this.l,this.a,this.b)},Zo.rgb=gt;var Ya=gt.prototype=new et;Ya.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new gt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new gt(u,u,u)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new gt(n*this.r,n*this.g,n*this.b)},Ya.hsl=function(){return yt(this.r,this.g,this.b)},Ya.toString=function(){return"#"+dt(this.r)+dt(this.g)+dt(this.b)};var Ia=Zo.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ia.forEach(function(n,t){Ia.set(n,pt(t))}),Zo.functor=bt,Zo.xhr=St(wt),Zo.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=kt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(l>=s)return o;if(u)return u=!1,i;var t=l;if(34===n.charCodeAt(t)){for(var e=t;e++<s;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}l=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++l):10===r&&(u=!0),n.substring(t+1,e).replace(/""/g,'"')}for(;s>l;){var r=n.charCodeAt(l++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(l)&&(++l,++a);else if(r!==c)continue;return n.substring(t,l-a)}return n.substring(t)}for(var r,u,i={},o={},a=[],s=n.length,l=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();(!t||(h=t(h,f++)))&&a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new h,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},Zo.csv=Zo.dsv(",","text/csv"),Zo.tsv=Zo.dsv(" ","text/tab-separated-values"),Zo.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=x().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return Z(n,r)};var Za,Va,Xa,$a,Ba,Wa=Wo[p(Wo,"requestAnimationFrame")]||function(n){setTimeout(n,17)};Zo.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Va?Va.n=i:Za=i,Va=i,Xa||($a=clearTimeout($a),Xa=1,Wa(At))},Zo.timer.flush=function(){Ct(),Nt()},Zo.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var Ja=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Lt);Zo.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=Zo.round(n,zt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),Ja[8+e/3]};var Ga=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,Ka=Zo.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=Zo.round(n,zt(n,t))).toFixed(Math.max(0,Math.min(20,zt(n*(1+1e-15),t))))}}),Qa=Zo.time={},nc=Date;Rt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){tc.setUTCDate.apply(this._,arguments)},setDay:function(){tc.setUTCDay.apply(this._,arguments)},setFullYear:function(){tc.setUTCFullYear.apply(this._,arguments)},setHours:function(){tc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){tc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){tc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){tc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){tc.setUTCSeconds.apply(this._,arguments)},setTime:function(){tc.setTime.apply(this._,arguments)}};var tc=Date.prototype;Qa.year=Dt(function(n){return n=Qa.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),Qa.years=Qa.year.range,Qa.years.utc=Qa.year.utc.range,Qa.day=Dt(function(n){var t=new nc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),Qa.days=Qa.day.range,Qa.days.utc=Qa.day.utc.range,Qa.dayOfYear=function(n){var t=Qa.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=Qa[n]=Dt(function(n){return(n=Qa.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=Qa.year(n).getDay();return Math.floor((Qa.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});Qa[n+"s"]=e.range,Qa[n+"s"].utc=e.utc.range,Qa[n+"OfYear"]=function(n){var e=Qa.year(n).getDay();return Math.floor((Qa.dayOfYear(n)+(e+t)%7)/7)}}),Qa.week=Qa.sunday,Qa.weeks=Qa.sunday.range,Qa.weeks.utc=Qa.sunday.utc.range,Qa.weekOfYear=Qa.sundayOfYear;var ec={"-":"",_:" ",0:"0"},rc=/^\s*\d+/,uc=/^%/;Zo.locale=function(n){return{numberFormat:Tt(n),timeFormat:Ut(n)}};var ic=Zo.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});Zo.format=ic.numberFormat,Zo.geo={},ue.prototype={s:0,t:0,add:function(n){ie(n,this.t,oc),ie(oc.s,this.s,this),this.s?this.t+=oc.t:this.s=oc.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var oc=new ue;Zo.geo.stream=function(n,t){n&&ac.hasOwnProperty(n.type)?ac[n.type](n,t):oe(n,t)};var ac={Feature:function(n,t){oe(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)oe(e[r].geometry,t)}},cc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){ae(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)ae(e[r],t,0)},Polygon:function(n,t){ce(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)ce(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)oe(e[r],t)}};Zo.geo.area=function(n){return sc=0,Zo.geo.stream(n,fc),sc};var sc,lc=new ue,fc={sphere:function(){sc+=4*ba},point:v,lineStart:v,lineEnd:v,polygonStart:function(){lc.reset(),fc.lineStart=se},polygonEnd:function(){var n=2*lc;sc+=0>n?4*ba+n:n,fc.lineStart=fc.lineEnd=fc.point=v}};Zo.geo.bounds=function(){function n(n,t){x.push(M=[l=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=le([t*Aa,e*Aa]);if(m){var u=he(m,r),i=[u[1],-u[0],0],o=he(i,u);ve(o),o=de(o);var c=t-p,s=c>0?1:-1,v=o[0]*Ca*s,d=ua(c)>180;if(d^(v>s*p&&s*t>v)){var y=o[1]*Ca;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>s*p&&s*t>v)){var y=-o[1]*Ca;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t):h>=l?(l>t&&(l=t),t>h&&(h=t)):t>p?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t)}else n(t,e);m=r,p=t}function e(){_.point=t}function r(){M[0]=l,M[1]=h,_.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ua(r)>180?r+(r>0?360:-360):r}else v=n,d=e;fc.point(n,e),t(n,e)}function i(){fc.lineStart()}function o(){u(v,d),fc.lineEnd(),ua(y)>ka&&(l=-(h=180)),M[0]=l,M[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function s(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var l,f,h,g,p,v,d,m,y,x,M,_={point:n,lineStart:e,lineEnd:r,polygonStart:function(){_.point=u,_.lineStart=i,_.lineEnd=o,y=0,fc.polygonStart()},polygonEnd:function(){fc.polygonEnd(),_.point=n,_.lineStart=e,_.lineEnd=r,0>lc?(l=-(h=180),f=-(g=90)):y>ka?g=90:-ka>y&&(f=-90),M[0]=l,M[1]=h}};return function(n){g=h=-(l=f=1/0),x=[],Zo.geo.stream(n,_);var t=x.length;if(t){x.sort(c);for(var e,r=1,u=x[0],i=[u];t>r;++r)e=x[r],s(e[0],u)||s(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e); - for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,l=e[0],h=u[1])}return x=M=null,1/0===l||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[l,f],[h,g]]}}(),Zo.geo.centroid=function(n){hc=gc=pc=vc=dc=mc=yc=xc=Mc=_c=bc=0,Zo.geo.stream(n,wc);var t=Mc,e=_c,r=bc,u=t*t+e*e+r*r;return Ea>u&&(t=mc,e=yc,r=xc,ka>gc&&(t=pc,e=vc,r=dc),u=t*t+e*e+r*r,Ea>u)?[0/0,0/0]:[Math.atan2(e,t)*Ca,G(r/Math.sqrt(u))*Ca]};var hc,gc,pc,vc,dc,mc,yc,xc,Mc,_c,bc,wc={sphere:v,point:ye,lineStart:Me,lineEnd:_e,polygonStart:function(){wc.lineStart=be},polygonEnd:function(){wc.lineStart=Me}},Sc=Ae(we,Te,Re,[-ba,-ba/2]),kc=1e9;Zo.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ue(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(Zo.geo.conicEqualArea=function(){return He(Fe)}).raw=Fe,Zo.geo.albers=function(){return Zo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},Zo.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=Zo.geo.albers(),o=Zo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=Zo.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var s=i.scale(),l=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[l-.455*s,f-.238*s],[l+.455*s,f+.238*s]]).stream(c).point,r=o.translate([l-.307*s,f+.201*s]).clipExtent([[l-.425*s+ka,f+.12*s+ka],[l-.214*s-ka,f+.234*s-ka]]).stream(c).point,u=a.translate([l-.205*s,f+.212*s]).clipExtent([[l-.214*s+ka,f+.166*s+ka],[l-.115*s-ka,f+.234*s-ka]]).stream(c).point,n},n.scale(1070)};var Ec,Ac,Cc,Nc,zc,Lc,Tc={point:v,lineStart:v,lineEnd:v,polygonStart:function(){Ac=0,Tc.lineStart=Oe},polygonEnd:function(){Tc.lineStart=Tc.lineEnd=Tc.point=v,Ec+=ua(Ac/2)}},qc={point:Ye,lineStart:v,lineEnd:v,polygonStart:v,polygonEnd:v},Rc={point:Ve,lineStart:Xe,lineEnd:$e,polygonStart:function(){Rc.lineStart=Be},polygonEnd:function(){Rc.point=Ve,Rc.lineStart=Xe,Rc.lineEnd=$e}};Zo.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),Zo.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Ec=0,Zo.geo.stream(n,u(Tc)),Ec},n.centroid=function(n){return pc=vc=dc=mc=yc=xc=Mc=_c=bc=0,Zo.geo.stream(n,u(Rc)),bc?[Mc/bc,_c/bc]:xc?[mc/xc,yc/xc]:dc?[pc/dc,vc/dc]:[0/0,0/0]},n.bounds=function(n){return zc=Lc=-(Cc=Nc=1/0),Zo.geo.stream(n,u(qc)),[[Cc,Nc],[zc,Lc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||Ge(n):wt,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new Ie:new We(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(Zo.geo.albersUsa()).context(null)},Zo.geo.transform=function(n){return{stream:function(t){var e=new Ke(t);for(var r in n)e[r]=n[r];return e}}},Ke.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},Zo.geo.projection=nr,Zo.geo.projectionMutator=tr,(Zo.geo.equirectangular=function(){return nr(rr)}).raw=rr.invert=rr,Zo.geo.rotation=function(n){function t(t){return t=n(t[0]*Aa,t[1]*Aa),t[0]*=Ca,t[1]*=Ca,t}return n=ir(n[0]%360*Aa,n[1]*Aa,n.length>2?n[2]*Aa:0),t.invert=function(t){return t=n.invert(t[0]*Aa,t[1]*Aa),t[0]*=Ca,t[1]*=Ca,t},t},ur.invert=rr,Zo.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=ir(-n[0]*Aa,-n[1]*Aa,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Ca,n[1]*=Ca}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=sr((t=+r)*Aa,u*Aa),n):t},n.precision=function(r){return arguments.length?(e=sr(t*Aa,(u=+r)*Aa),n):u},n.angle(90)},Zo.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Aa,u=n[1]*Aa,i=t[1]*Aa,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),s=Math.cos(u),l=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=s*l-c*f*a)*e),c*l+s*f*a)},Zo.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return Zo.range(Math.ceil(i/d)*d,u,d).map(h).concat(Zo.range(Math.ceil(s/m)*m,c,m).map(g)).concat(Zo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ua(n%d)>ka}).map(l)).concat(Zo.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ua(n%m)>ka}).map(f))}var e,r,u,i,o,a,c,s,l,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(s).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],s=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),s>c&&(t=s,s=c,c=t),n.precision(y)):[[i,s],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,l=fr(a,o,90),f=hr(r,e,y),h=fr(s,c,90),g=hr(i,u,y),n):y},n.majorExtent([[-180,-90+ka],[180,90-ka]]).minorExtent([[-180,-80-ka],[180,80+ka]])},Zo.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=gr,u=pr;return n.distance=function(){return Zo.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},Zo.geo.interpolate=function(n,t){return vr(n[0]*Aa,n[1]*Aa,t[0]*Aa,t[1]*Aa)},Zo.geo.length=function(n){return Dc=0,Zo.geo.stream(n,Pc),Dc};var Dc,Pc={sphere:v,point:v,lineStart:dr,lineEnd:v,polygonStart:v,polygonEnd:v},Uc=mr(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(Zo.geo.azimuthalEqualArea=function(){return nr(Uc)}).raw=Uc;var jc=mr(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},wt);(Zo.geo.azimuthalEquidistant=function(){return nr(jc)}).raw=jc,(Zo.geo.conicConformal=function(){return He(yr)}).raw=yr,(Zo.geo.conicEquidistant=function(){return He(xr)}).raw=xr;var Hc=mr(function(n){return 1/n},Math.atan);(Zo.geo.gnomonic=function(){return nr(Hc)}).raw=Hc,Mr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Sa]},(Zo.geo.mercator=function(){return _r(Mr)}).raw=Mr;var Fc=mr(function(){return 1},Math.asin);(Zo.geo.orthographic=function(){return nr(Fc)}).raw=Fc;var Oc=mr(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(Zo.geo.stereographic=function(){return nr(Oc)}).raw=Oc,br.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Sa]},(Zo.geo.transverseMercator=function(){var n=_r(br),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=br,Zo.geom={},Zo.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=bt(e),i=bt(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(Er),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var s=kr(a),l=kr(c),f=l[0]===s[0],h=l[l.length-1]===s[s.length-1],g=[];for(t=s.length-1;t>=0;--t)g.push(n[a[s[t]][2]]);for(t=+f;t<l.length-h;++t)g.push(n[a[l[t]][2]]);return g}var e=wr,r=Sr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},Zo.geom.polygon=function(n){return sa(n,Yc),n};var Yc=Zo.geom.polygon.prototype=[];Yc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Yc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Yc.clip=function(n){for(var t,e,r,u,i,o,a=Nr(n),c=-1,s=this.length-Nr(this),l=this[s-1];++c<s;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Ar(o,l,u)?(Ar(i,l,u)||n.push(Cr(i,o,l,u)),n.push(o)):Ar(i,l,u)&&n.push(Cr(i,o,l,u)),i=o;a&&n.push(n[0]),l=u}return n};var Ic,Zc,Vc,Xc,$c,Bc=[],Wc=[];Ur.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Hr),t.length},Wr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},Jr.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=nu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(Kr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Qr(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(Qr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Kr(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?nu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return n.C=!1,void 0;do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,Kr(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,Qr(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,Kr(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,Qr(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,Kr(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,Qr(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},Zo.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return tu(e(n),a).cells.forEach(function(e,a){var c=e.edges,s=e.site,l=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):s.x>=r&&s.x<=i&&s.y>=u&&s.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];l.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/ka)*ka,y:Math.round(o(n,t)/ka)*ka,i:t}})}var r=wr,u=Sr,i=r,o=u,a=Jc;return n?t(n):(t.links=function(n){return tu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return tu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Hr),c=-1,s=a.length,l=a[s-1].edge,f=l.l===o?l.r:l.l;++c<s;)u=l,i=f,l=a[c].edge,f=l.l===o?l.r:l.l,r<i.i&&r<f.i&&ru(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=bt(r=n),t):r},t.y=function(n){return arguments.length?(o=bt(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?Jc:n,t):a===Jc?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===Jc?null:a&&a[1]},t)};var Jc=[[-1e6,-1e6],[1e6,1e6]];Zo.geom.delaunay=function(n){return Zo.geom.voronoi().triangles(n)},Zo.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,l=n.y;if(null!=c)if(ua(c-e)+ua(l-r)<.01)s(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,s(n,f,c,l,u,i,o,a),s(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else s(n,t,e,r,u,i,o,a)}function s(n,t,e,r,u,o,a,c){var s=.5*(u+a),l=.5*(o+c),f=e>=s,h=r>=l,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=ou()),f?u=s:a=s,h?o=l:c=l,i(n,t,e,r,u,o,a,c)}var l,f,h,g,p,v,d,m,y,x=bt(a),M=bt(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)l=n[g],l.x<v&&(v=l.x),l.y<d&&(d=l.y),l.x>m&&(m=l.x),l.y>y&&(y=l.y),f.push(l.x),h.push(l.y);else for(g=0;p>g;++g){var _=+x(l=n[g],g),b=+M(l,g);v>_&&(v=_),d>b&&(d=b),_>m&&(m=_),b>y&&(y=b),f.push(_),h.push(b)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=ou();if(k.add=function(n){i(k,n,+x(n,++g),+M(n,g),v,d,m,y)},k.visit=function(n){au(n,k,v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=l=null,k}var o,a=wr,c=Sr;return(o=arguments.length)?(a=uu,c=iu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},Zo.interpolateRgb=cu,Zo.interpolateObject=su,Zo.interpolateNumber=lu,Zo.interpolateString=fu;var Gc=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Kc=new RegExp(Gc.source,"g");Zo.interpolate=hu,Zo.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ia.has(t)||/^(#|rgb\(|hsl\()/.test(t)?cu:fu:t instanceof et?cu:Array.isArray(t)?gu:"object"===e&&isNaN(t)?su:lu)(n,t)}],Zo.interpolateArray=gu;var Qc=function(){return wt},ns=Zo.map({linear:Qc,poly:Mu,quad:function(){return mu},cubic:function(){return yu},sin:function(){return _u},exp:function(){return bu},circle:function(){return wu},elastic:Su,back:ku,bounce:function(){return Eu}}),ts=Zo.map({"in":wt,out:vu,"in-out":du,"out-in":function(n){return du(vu(n))}});Zo.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.substring(0,t):n,r=t>=0?n.substring(t+1):"in";return e=ns.get(e)||Qc,r=ts.get(r)||wt,pu(r(e.apply(null,Vo.call(arguments,1))))},Zo.interpolateHcl=Au,Zo.interpolateHsl=Cu,Zo.interpolateLab=Nu,Zo.interpolateRound=zu,Zo.transform=function(n){var t=$o.createElementNS(Zo.ns.prefix.svg,"g");return(Zo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Lu(e?e.matrix:es)})(n)},Lu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var es={a:1,b:0,c:0,d:1,e:0,f:0};Zo.interpolateTransform=Du,Zo.layout={},Zo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(ju(n[e]));return t}},Zo.layout.chord=function(){function n(){var n,s,f,h,g,p={},v=[],d=Zo.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(s=0,g=-1;++g<i;)s+=u[h][g];v.push(s),m.push(Zo.range(i)),n+=s}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(wa-l*i)/n,s=0,h=-1;++h<i;){for(f=s,g=-1;++g<i;){var y=d[h],x=m[y][g],M=u[y][x],_=s,b=s+=M*n;p[y+"-"+x]={index:y,subindex:x,startAngle:_,endAngle:b,value:M}}r[y]={index:y,startAngle:f,endAngle:s,value:(s-f)/n},s+=l}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,s={},l=0;return s.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,s):u},s.padding=function(n){return arguments.length?(l=n,e=r=null,s):l},s.sortGroups=function(n){return arguments.length?(o=n,e=r=null,s):o},s.sortSubgroups=function(n){return arguments.length?(a=n,e=null,s):a},s.sortChords=function(n){return arguments.length?(c=n,e&&t(),s):c},s.chords=function(){return e||n(),e},s.groups=function(){return r||n(),r},s},Zo.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var s=t.charge/c;n.px-=i*s,n.py-=o*s}return!0}if(t.point&&c&&p>c){var s=t.pointCharge/c;n.px-=i*s,n.py-=o*s}}return!t.charge}}function t(n){n.px=Zo.event.x,n.py=Zo.event.y,a.resume()}var e,r,u,i,o,a={},c=Zo.dispatch("start","tick","end"),s=[1,1],l=.9,f=rs,h=us,g=-30,p=is,v=.1,d=.64,m=[],y=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,x,M,_=m.length,b=y.length;for(e=0;b>e;++e)a=y[e],f=a.source,h=a.target,x=h.x-f.x,M=h.y-f.y,(p=x*x+M*M)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,x*=p,M*=p,h.x-=x*(d=f.weight/(h.weight+f.weight)),h.y-=M*d,f.x+=x*(d=1-d),f.y+=M*d);if((d=r*v)&&(x=s[0]/2,M=s[1]/2,e=-1,d))for(;++e<_;)a=m[e],a.x+=(x-a.x)*d,a.y+=(M-a.y)*d;if(g)for(Vu(t=Zo.geom.quadtree(m),r,o),e=-1;++e<_;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<_;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*l,a.y-=(a.py-(a.py=a.y))*l);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(y=n,a):y},a.size=function(n){return arguments.length?(s=n,a):s},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(l=+n,a):l},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),Zo.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=y[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,s=o.length;++a<s;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,l=y.length,p=s[0],v=s[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;l>t;++t)r=y[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;l>t;++t)u[t]=+f.call(this,y[t],t);else for(t=0;l>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;l>t;++t)i[t]=+h.call(this,y[t],t);else for(t=0;l>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=Zo.behavior.drag().origin(wt).on("dragstart.force",Ou).on("drag.force",t).on("dragend.force",Yu)),arguments.length?(this.on("mouseover.force",Iu).on("mouseout.force",Zu).call(e),void 0):e},Zo.rebind(a,c,"on")};var rs=20,us=1,is=1/0;Zo.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(s=e.call(n,i,i.depth))&&(c=s.length)){for(var c,s,l;--c>=0;)o.push(l=s[c]),l.parent=i,l.depth=i.depth+1;r&&(i.value=0),i.children=s}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Bu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=Gu,e=Wu,r=Ju;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&($u(t,function(n){n.children&&(n.value=0)}),Bu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},Zo.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,s=-1;for(r=t.value?r/t.value:0;++s<o;)n(a=i[s],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=Zo.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Xu(e,r)},Zo.layout.pie=function(){function n(i){var o=i.map(function(e,r){return+t.call(n,e,r)}),a=+("function"==typeof r?r.apply(this,arguments):r),c=(("function"==typeof u?u.apply(this,arguments):u)-a)/Zo.sum(o),s=Zo.range(i.length);null!=e&&s.sort(e===os?function(n,t){return o[t]-o[n]}:function(n,t){return e(i[n],i[t])});var l=[];return s.forEach(function(n){var t;l[n]={data:i[n],value:t=o[n],startAngle:a,endAngle:a+=t*c}}),l}var t=Number,e=os,r=0,u=wa;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n};var os={};Zo.layout.stack=function(){function n(a,c){var s=a.map(function(e,r){return t.call(n,e,r)}),l=s.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,l,c);s=Zo.permute(s,f),l=Zo.permute(l,f);var h,g,p,v=r.call(n,l,c),d=s.length,m=s[0].length;for(g=0;m>g;++g)for(u.call(n,s[0][g],p=v[g],l[0][g][1]),h=1;d>h;++h)u.call(n,s[h][g],p+=l[h-1][g][1],l[h][g][1]);return a}var t=wt,e=ei,r=ri,u=ti,i=Qu,o=ni;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:as.get(t)||ei,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:cs.get(t)||ri,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var as=Zo.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(ui),i=n.map(ii),o=Zo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,s=[],l=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],s.push(e)):(c+=i[e],l.push(e));return l.reverse().concat(s)},reverse:function(n){return Zo.range(n.length).reverse()},"default":ei}),cs=Zo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,s,l=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=s=0,e=1;h>e;++e){for(t=0,u=0;l>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];l>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,s>c&&(s=c)}for(e=0;h>e;++e)g[e]-=s;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ri});Zo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],s=n.map(e,this),l=r.call(this,s,i),f=u.call(this,l,s,i),i=-1,h=s.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=s[i],a>=l[0]&&a<=l[1]&&(o=c[Zo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=si,u=ai;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=bt(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return ci(n,t)}:bt(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},Zo.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],s=u[1],l=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Bu(a,function(n){n.r=+l(n.value)}),Bu(a,pi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/s))/2;Bu(a,function(n){n.r+=f}),Bu(a,pi),Bu(a,function(n){n.r-=f})}return mi(a,c/2,s/2,t?1:1/Math.max(2*a.r/c,2*a.r/s)),o}var t,e=Zo.layout.hierarchy().sort(li),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Xu(n,e)},Zo.layout.tree=function(){function n(n,u){var l=o.call(this,n,u),f=l[0],h=t(f);if(Bu(h,e),h.parent.m=-h.z,$u(h,r),s)$u(f,i);else{var g=f,p=f,v=f;$u(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);$u(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return l}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){wi(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],s=u.m,l=i.m,f=o.m,h=c.m;o=_i(o),u=Mi(u),o&&u;)c=Mi(c),i=_i(i),i.a=n,r=o.z+f-u.z-s+a(o._,u._),r>0&&(bi(Si(o,n,e),n,r),s+=r,l+=r),f+=o.m,s+=u.m,h+=c.m,l+=i.m;o&&!_i(i)&&(i.t=o,i.m+=f-l),u&&!Mi(c)&&(c.t=u,c.m+=s-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=Zo.layout.hierarchy().sort(null).value(null),a=xi,c=[1,1],s=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(s=null==(c=t)?i:null,n):s?null:c},n.nodeSize=function(t){return arguments.length?(s=null==(c=t)?null:i,n):s?c:null},Xu(n,o)},Zo.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],s=0;Bu(c,function(n){var t=n.children;t&&t.length?(n.x=Ei(t),n.y=ki(t)):(n.x=o?s+=e(n,o):0,n.y=0,o=n)});var l=Ai(c),f=Ci(c),h=l.x-e(l,f)/2,g=f.x+e(f,l)/2;return Bu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=Zo.layout.hierarchy().sort(null).value(null),e=xi,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Xu(n,t)},Zo.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,s=f(e),l=[],h=i.slice(),p=1/0,v="slice"===g?s.dx:"dice"===g?s.dy:"slice-dice"===g?1&e.depth?s.dy:s.dx:Math.min(s.dx,s.dy);for(n(h,s.dx*s.dy/e.value),l.area=0;(c=h.length)>0;)l.push(o=h[c-1]),l.area+=o.area,"squarify"!==g||(a=r(l,v))<=p?(h.pop(),p=a):(l.area-=l.pop().area,u(l,v,s,!1),v=Math.min(s.dx,s.dy),l.length=l.area=0,p=1/0);l.length&&(u(l,v,s,!0),l.length=l.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,s=e.y,l=t?c(n.area/t):0;if(t==e.dx){for((r||l>e.dy)&&(l=e.dy);++i<o;)u=n[i],u.x=a,u.y=s,u.dy=l,a+=u.dx=Math.min(e.x+e.dx-a,l?c(u.area/l):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=l,e.dy-=l}else{for((r||l>e.dx)&&(l=e.dx);++i<o;)u=n[i],u.x=a,u.y=s,u.dx=l,s+=u.dy=Math.min(e.y+e.dy-s,l?c(u.area/l):0);u.z=!1,u.dy+=e.y+e.dy-s,e.x+=l,e.dx-=l}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=s[0],i.dy=s[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=Zo.layout.hierarchy(),c=Math.round,s=[1,1],l=null,f=Ni,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));return i.size=function(n){return arguments.length?(s=n,i):s},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ni(t):zi(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return zi(t,n)}if(!arguments.length)return l;var r;return f=null==(l=n)?Ni:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Xu(i,a)},Zo.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=Zo.random.normal.apply(Zo,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=Zo.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},Zo.scale={};var ss={floor:wt,ceil:wt};Zo.scale.linear=function(){return Ui([0,1],[0,1],hu,!1)};var ls={s:1,g:1,p:1,r:1,e:1};Zo.scale.log=function(){return Vi(Zo.scale.linear().domain([0,1]),10,!0,[1,10])};var fs=Zo.format(".0e"),hs={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};Zo.scale.pow=function(){return Xi(Zo.scale.linear(),1,[0,1])},Zo.scale.sqrt=function(){return Zo.scale.pow().exponent(.5)},Zo.scale.ordinal=function(){return Bi([],{t:"range",a:[[]]})},Zo.scale.category10=function(){return Zo.scale.ordinal().range(gs)},Zo.scale.category20=function(){return Zo.scale.ordinal().range(ps)},Zo.scale.category20b=function(){return Zo.scale.ordinal().range(vs)},Zo.scale.category20c=function(){return Zo.scale.ordinal().range(ds)};var gs=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(vt),ps=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(vt),vs=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(vt),ds=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(vt);Zo.scale.quantile=function(){return Wi([],[])},Zo.scale.quantize=function(){return Ji(0,1,[0,1])},Zo.scale.threshold=function(){return Gi([.5],[0,1])},Zo.scale.identity=function(){return Ki([0,1])},Zo.svg={},Zo.svg.arc=function(){function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+ms,a=u.apply(this,arguments)+ms,c=(o>a&&(c=o,o=a,a=c),a-o),s=ba>c?"0":"1",l=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a); - return c>=ys?n?"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"M0,"+n+"A"+n+","+n+" 0 1,0 0,"+-n+"A"+n+","+n+" 0 1,0 0,"+n+"Z":"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":n?"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L"+n*h+","+n*g+"A"+n+","+n+" 0 "+s+",0 "+n*l+","+n*f+"Z":"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L0,0"+"Z"}var t=Qi,e=no,r=to,u=eo;return n.innerRadius=function(e){return arguments.length?(t=bt(e),n):t},n.outerRadius=function(t){return arguments.length?(e=bt(t),n):e},n.startAngle=function(t){return arguments.length?(r=bt(t),n):r},n.endAngle=function(t){return arguments.length?(u=bt(t),n):u},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,i=(r.apply(this,arguments)+u.apply(this,arguments))/2+ms;return[Math.cos(i)*n,Math.sin(i)*n]},n};var ms=-Sa,ys=wa-ka;Zo.svg.line=function(){return ro(wt)};var xs=Zo.map({linear:uo,"linear-closed":io,step:oo,"step-before":ao,"step-after":co,basis:po,"basis-open":vo,"basis-closed":mo,bundle:yo,cardinal:fo,"cardinal-open":so,"cardinal-closed":lo,monotone:So});xs.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Ms=[0,2/3,1/3,0],_s=[0,1/3,2/3,0],bs=[0,1/6,2/3,1/6];Zo.svg.line.radial=function(){var n=ro(ko);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},ao.reverse=co,co.reverse=ao,Zo.svg.area=function(){return Eo(wt)},Zo.svg.area.radial=function(){var n=Eo(ko);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},Zo.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),s=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,s)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,s.r,s.p0)+r(s.r,s.p1,s.a1-s.a0)+u(s.r,s.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)+ms,l=s.call(n,u,r)+ms;return{r:i,a0:o,a1:l,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(l),i*Math.sin(l)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>ba)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=gr,o=pr,a=Ao,c=to,s=eo;return n.radius=function(t){return arguments.length?(a=bt(t),n):a},n.source=function(t){return arguments.length?(i=bt(t),n):i},n.target=function(t){return arguments.length?(o=bt(t),n):o},n.startAngle=function(t){return arguments.length?(c=bt(t),n):c},n.endAngle=function(t){return arguments.length?(s=bt(t),n):s},n},Zo.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=gr,e=pr,r=Co;return n.source=function(e){return arguments.length?(t=bt(e),n):t},n.target=function(t){return arguments.length?(e=bt(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},Zo.svg.diagonal.radial=function(){var n=Zo.svg.diagonal(),t=Co,e=n.projection;return n.projection=function(n){return arguments.length?e(No(t=n)):t},n},Zo.svg.symbol=function(){function n(n,r){return(ws.get(t.call(this,n,r))||To)(e.call(this,n,r))}var t=Lo,e=zo;return n.type=function(e){return arguments.length?(t=bt(e),n):t},n.size=function(t){return arguments.length?(e=bt(t),n):e},n};var ws=Zo.map({circle:To,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*As)),e=t*As;return"M0,"+-t+"L"+e+",0"+" 0,"+t+" "+-e+",0"+"Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/Es),e=t*Es/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/Es),e=t*Es/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});Zo.svg.symbolTypes=ws.keys();var Ss,ks,Es=Math.sqrt(3),As=Math.tan(30*Aa),Cs=[],Ns=0;Cs.call=pa.call,Cs.empty=pa.empty,Cs.node=pa.node,Cs.size=pa.size,Zo.transition=function(n){return arguments.length?Ss?n.transition():n:ma.transition()},Zo.transition.prototype=Cs,Cs.select=function(n){var t,e,r,u=this.id,i=[];n=b(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]);for(var c=this[o],s=-1,l=c.length;++s<l;)(r=c[s])&&(e=n.call(r,r.__data__,s,o))?("__data__"in r&&(e.__data__=r.__data__),Po(e,s,u,r.__transition__[u]),t.push(e)):t.push(null)}return qo(i,u)},Cs.selectAll=function(n){var t,e,r,u,i,o=this.id,a=[];n=w(n);for(var c=-1,s=this.length;++c<s;)for(var l=this[c],f=-1,h=l.length;++f<h;)if(r=l[f]){i=r.__transition__[o],e=n.call(r,r.__data__,f,c),a.push(t=[]);for(var g=-1,p=e.length;++g<p;)(u=e[g])&&Po(u,g,o,i),t.push(u)}return qo(a,o)},Cs.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=R(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return qo(u,this.id)},Cs.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):P(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Cs.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Du:hu,a=Zo.ns.qualify(n);return Ro(this,"attr."+n,t,a.local?i:u)},Cs.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=Zo.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Cs.style=function(n,t,e){function r(){this.style.removeProperty(n)}function u(t){return null==t?r:(t+="",function(){var r,u=Wo.getComputedStyle(this,null).getPropertyValue(n);return u!==t&&(r=hu(u,t),function(t){this.style.setProperty(n,r(t),e)})})}var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(t="");for(e in n)this.style(e,n[e],t);return this}e=""}return Ro(this,"style."+n,t,u)},Cs.styleTween=function(n,t,e){function r(r,u){var i=t.call(this,r,u,Wo.getComputedStyle(this,null).getPropertyValue(n));return i&&function(t){this.style.setProperty(n,i(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,r)},Cs.text=function(n){return Ro(this,"text",n,Do)},Cs.remove=function(){return this.each("end.transition",function(){var n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Cs.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof n&&(n=Zo.ease.apply(Zo,arguments)),P(this,function(e){e.__transition__[t].ease=n}))},Cs.delay=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].delay:P(this,"function"==typeof n?function(e,r,u){e.__transition__[t].delay=+n.call(e,e.__data__,r,u)}:(n=+n,function(e){e.__transition__[t].delay=n}))},Cs.duration=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].duration:P(this,"function"==typeof n?function(e,r,u){e.__transition__[t].duration=Math.max(1,n.call(e,e.__data__,r,u))}:(n=Math.max(1,n),function(e){e.__transition__[t].duration=n}))},Cs.each=function(n,t){var e=this.id;if(arguments.length<2){var r=ks,u=Ss;Ss=e,P(this,function(t,r,u){ks=t.__transition__[e],n.call(t,t.__data__,r,u)}),ks=r,Ss=u}else P(this,function(r){var u=r.__transition__[e];(u.event||(u.event=Zo.dispatch("start","end"))).on(n,t)});return this},Cs.transition=function(){for(var n,t,e,r,u=this.id,i=++Ns,o=[],a=0,c=this.length;c>a;a++){o.push(n=[]);for(var t=this[a],s=0,l=t.length;l>s;s++)(e=t[s])&&(r=Object.create(e.__transition__[u]),r.delay+=r.duration,Po(e,s,i,r)),n.push(e)}return qo(o,i)},Zo.svg.axis=function(){function n(n){n.each(function(){var n,s=Zo.select(this),l=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):wt:t,p=s.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",ka),d=Zo.transition(p.exit()).style("opacity",ka).remove(),m=Zo.transition(p.order()).style("opacity",1),y=Ti(f),x=s.selectAll(".domain").data([0]),M=(x.enter().append("path").attr("class","domain"),Zo.transition(x));v.append("line"),v.append("text");var _=v.select("line"),b=m.select("line"),w=p.select("text").text(g),S=v.select("text"),k=m.select("text");switch(r){case"bottom":n=Uo,_.attr("y2",u),S.attr("y",Math.max(u,0)+o),b.attr("x2",0).attr("y2",u),k.attr("x",0).attr("y",Math.max(u,0)+o),w.attr("dy",".71em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+i+"V0H"+y[1]+"V"+i);break;case"top":n=Uo,_.attr("y2",-u),S.attr("y",-(Math.max(u,0)+o)),b.attr("x2",0).attr("y2",-u),k.attr("x",0).attr("y",-(Math.max(u,0)+o)),w.attr("dy","0em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+-i+"V0H"+y[1]+"V"+-i);break;case"left":n=jo,_.attr("x2",-u),S.attr("x",-(Math.max(u,0)+o)),b.attr("x2",-u).attr("y2",0),k.attr("x",-(Math.max(u,0)+o)).attr("y",0),w.attr("dy",".32em").style("text-anchor","end"),M.attr("d","M"+-i+","+y[0]+"H0V"+y[1]+"H"+-i);break;case"right":n=jo,_.attr("x2",u),S.attr("x",Math.max(u,0)+o),b.attr("x2",u).attr("y2",0),k.attr("x",Math.max(u,0)+o).attr("y",0),w.attr("dy",".32em").style("text-anchor","start"),M.attr("d","M"+i+","+y[0]+"H0V"+y[1]+"H"+i)}if(f.rangeBand){var E=f,A=E.rangeBand()/2;l=f=function(n){return E(n)+A}}else l.rangeBand?l=f:d.call(n,f);v.call(n,l),m.call(n,f)})}var t,e=Zo.scale.linear(),r=zs,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Ls?t+"":zs,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var zs="bottom",Ls={top:1,right:1,bottom:1,left:1};Zo.svg.brush=function(){function n(i){i.each(function(){var i=Zo.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=i.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),i.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=i.selectAll(".resize").data(p,wt);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Ts[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,f=Zo.transition(i),h=Zo.transition(o);c&&(l=Ti(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),e(f)),s&&(l=Ti(s),h.attr("y",l[0]).attr("height",l[1]-l[0]),r(f)),t(f)})}function t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+l[+/e$/.test(n)]+","+f[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",l[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",l[1]-l[0])}function r(n){n.select(".extent").attr("y",f[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",f[1]-f[0])}function u(){function u(){32==Zo.event.keyCode&&(C||(x=null,z[0]-=l[1],z[1]-=f[1],C=2),y())}function p(){32==Zo.event.keyCode&&2==C&&(z[0]+=l[1],z[1]+=f[1],C=0,y())}function v(){var n=Zo.mouse(_),u=!1;M&&(n[0]+=M[0],n[1]+=M[1]),C||(Zo.event.altKey?(x||(x=[(l[0]+l[1])/2,(f[0]+f[1])/2]),z[0]=l[+(n[0]<x[0])],z[1]=f[+(n[1]<x[1])]):x=null),E&&d(n,c,0)&&(e(S),u=!0),A&&d(n,s,1)&&(r(S),u=!0),u&&(t(S),w({type:"brush",mode:C?"move":"resize"}))}function d(n,t,e){var r,u,a=Ti(t),c=a[0],s=a[1],p=z[e],v=e?f:l,d=v[1]-v[0];return C&&(c-=p,s-=d+p),r=(e?g:h)?Math.max(c,Math.min(s,n[e])):n[e],C?u=(r+=p)+d:(x&&(p=Math.max(c,Math.min(s,2*x[e]-r))),r>p?(u=r,r=p):u=p),v[0]!=r||v[1]!=u?(e?o=null:i=null,v[0]=r,v[1]=u,!0):void 0}function m(){v(),S.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),Zo.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),N(),w({type:"brushend"})}var x,M,_=this,b=Zo.select(Zo.event.target),w=a.of(_,arguments),S=Zo.select(_),k=b.datum(),E=!/^(n|s)$/.test(k)&&c,A=!/^(e|w)$/.test(k)&&s,C=b.classed("extent"),N=I(),z=Zo.mouse(_),L=Zo.select(Wo).on("keydown.brush",u).on("keyup.brush",p);if(Zo.event.changedTouches?L.on("touchmove.brush",v).on("touchend.brush",m):L.on("mousemove.brush",v).on("mouseup.brush",m),S.interrupt().selectAll("*").interrupt(),C)z[0]=l[0]-z[0],z[1]=f[0]-z[1];else if(k){var T=+/w$/.test(k),q=+/^n/.test(k);M=[l[1-T]-z[0],f[1-q]-z[1]],z[0]=l[T],z[1]=f[q]}else Zo.event.altKey&&(x=z.slice());S.style("pointer-events","none").selectAll(".resize").style("display",null),Zo.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),v()}var i,o,a=M(n,"brushstart","brush","brushend"),c=null,s=null,l=[0,0],f=[0,0],h=!0,g=!0,p=qs[0];return n.event=function(n){n.each(function(){var n=a.of(this,arguments),t={x:l,y:f,i:i,j:o},e=this.__chart__||t;this.__chart__=t,Ss?Zo.select(this).transition().each("start.brush",function(){i=e.i,o=e.j,l=e.x,f=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=gu(l,t.x),r=gu(f,t.y);return i=o=null,function(u){l=t.x=e(u),f=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){i=t.i,o=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,p=qs[!c<<1|!s],n):c},n.y=function(t){return arguments.length?(s=t,p=qs[!c<<1|!s],n):s},n.clamp=function(t){return arguments.length?(c&&s?(h=!!t[0],g=!!t[1]):c?h=!!t:s&&(g=!!t),n):c&&s?[h,g]:c?h:s?g:null},n.extent=function(t){var e,r,u,a,h;return arguments.length?(c&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),i=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(h=e,e=r,r=h),(e!=l[0]||r!=l[1])&&(l=[e,r])),s&&(u=t[0],a=t[1],c&&(u=u[1],a=a[1]),o=[u,a],s.invert&&(u=s(u),a=s(a)),u>a&&(h=u,u=a,a=h),(u!=f[0]||a!=f[1])&&(f=[u,a])),n):(c&&(i?(e=i[0],r=i[1]):(e=l[0],r=l[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(h=e,e=r,r=h))),s&&(o?(u=o[0],a=o[1]):(u=f[0],a=f[1],s.invert&&(u=s.invert(u),a=s.invert(a)),u>a&&(h=u,u=a,a=h))),c&&s?[[e,u],[r,a]]:c?[e,r]:s&&[u,a])},n.clear=function(){return n.empty()||(l=[0,0],f=[0,0],i=o=null),n},n.empty=function(){return!!c&&l[0]==l[1]||!!s&&f[0]==f[1]},Zo.rebind(n,a,"on")};var Ts={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},qs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Rs=Qa.format=ic.timeFormat,Ds=Rs.utc,Ps=Ds("%Y-%m-%dT%H:%M:%S.%LZ");Rs.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Ho:Ps,Ho.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Ho.toString=Ps.toString,Qa.second=Dt(function(n){return new nc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),Qa.seconds=Qa.second.range,Qa.seconds.utc=Qa.second.utc.range,Qa.minute=Dt(function(n){return new nc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),Qa.minutes=Qa.minute.range,Qa.minutes.utc=Qa.minute.utc.range,Qa.hour=Dt(function(n){var t=n.getTimezoneOffset()/60;return new nc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),Qa.hours=Qa.hour.range,Qa.hours.utc=Qa.hour.utc.range,Qa.month=Dt(function(n){return n=Qa.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),Qa.months=Qa.month.range,Qa.months.utc=Qa.month.utc.range;var Us=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],js=[[Qa.second,1],[Qa.second,5],[Qa.second,15],[Qa.second,30],[Qa.minute,1],[Qa.minute,5],[Qa.minute,15],[Qa.minute,30],[Qa.hour,1],[Qa.hour,3],[Qa.hour,6],[Qa.hour,12],[Qa.day,1],[Qa.day,2],[Qa.week,1],[Qa.month,1],[Qa.month,3],[Qa.year,1]],Hs=Rs.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",we]]),Fs={range:function(n,t,e){return Zo.range(Math.ceil(n/e)*e,+t,e).map(Oo)},floor:wt,ceil:wt};js.year=Qa.year,Qa.scale=function(){return Fo(Zo.scale.linear(),js,Hs)};var Os=js.map(function(n){return[n[0].utc,n[1]]}),Ys=Ds.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",we]]);Os.year=Qa.year.utc,Qa.scale.utc=function(){return Fo(Zo.scale.linear(),Os,Ys)},Zo.text=St(function(n){return n.responseText}),Zo.json=function(n,t){return kt(n,"application/json",Yo,t)},Zo.html=function(n,t){return kt(n,"text/html",Io,t)},Zo.xml=St(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(Zo):"object"==typeof module&&module.exports&&(module.exports=Zo),this.d3=Zo}(); - - - var catalog = -{"packages":[{"name":"a","size":2,"imports":["b","c"],"cycleSegments":{},"cycleCount":0,"cycleSegmentCount":0},{"name":"b","size":1,"imports":["c"],"cycleSegments":{},"cycleCount":0,"cycleSegmentCount":0},{"name":"c","size":1,"imports":[],"cycleSegments":{},"cycleCount":0,"cycleSegmentCount":0},{"name":"u","size":2,"imports":["v"],"cycleSegments":{"u-v":{"s":"v","t":"u"},"v-u":{"s":"u","t":"v"}},"cycleCount":1,"cycleSegmentCount":2},{"name":"v","size":1,"imports":["u"],"cycleSegments":{"u-v":{"s":"v","t":"u"},"v-u":{"s":"u","t":"v"}},"cycleCount":1,"cycleSegmentCount":2},{"name":"x","size":1,"imports":["y"],"cycleSegments":{"y-x":{"s":"x","t":"y"},"z-y":{"s":"y","t":"z"},"x-z":{"s":"z","t":"x"}},"cycleCount":1,"cycleSegmentCount":3},{"name":"y","size":1,"imports":["z"],"cycleSegments":{"y-x":{"s":"x","t":"y"},"z-y":{"s":"y","t":"z"},"x-z":{"s":"z","t":"x"}},"cycleCount":1,"cycleSegmentCount":3},{"name":"z","size":1,"imports":["x"],"cycleSegments":{"y-x":{"s":"x","t":"y"},"z-y":{"s":"y","t":"z"},"x-z":{"s":"z","t":"x"}},"cycleCount":1,"cycleSegmentCount":3},{"name":"k","size":1,"imports":["l"],"cycleSegments":{"k-l":{"s":"l","t":"k"},"l-k":{"s":"k","t":"l"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"},"n-l":{"s":"l","t":"n"},"k-n":{"s":"n","t":"k"}},"cycleCount":3,"cycleSegmentCount":6},{"name":"l","size":1,"imports":["k","m","n"],"cycleSegments":{"k-l":{"s":"l","t":"k"},"l-k":{"s":"k","t":"l"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"},"n-l":{"s":"l","t":"n"},"k-n":{"s":"n","t":"k"}},"cycleCount":3,"cycleSegmentCount":6},{"name":"m","size":1,"imports":["n"],"cycleSegments":{"l-k":{"s":"k","t":"l"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"},"k-n":{"s":"n","t":"k"}},"cycleCount":1,"cycleSegmentCount":4},{"name":"n","size":1,"imports":["k"],"cycleSegments":{"l-k":{"s":"k","t":"l"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"},"n-l":{"s":"l","t":"n"},"k-n":{"s":"n","t":"k"}},"cycleCount":2,"cycleSegmentCount":5}],"cycleSegments":{"u-v":{"s":"v","t":"u"},"k-l":{"s":"l","t":"k"},"v-u":{"s":"u","t":"v"},"l-k":{"s":"k","t":"l"},"y-x":{"s":"x","t":"y"},"z-y":{"s":"y","t":"z"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"},"n-l":{"s":"l","t":"n"},"k-n":{"s":"n","t":"k"},"x-z":{"s":"z","t":"x"}},"summary":{"packages":12,"sources":14,"cycles":5,"cycleSegments":11}} - ; - - var diameter = 1000, - radius = diameter / 2, - innerRadius = radius - 300; - - var cluster = d3.layout.cluster() - .size([360, innerRadius]) - .sort(null) - .value(function(d) { return d.size; }); - - var bundle = d3.layout.bundle(); - - var line = d3.svg.line.radial() - .interpolate("bundle") - .tension(.75) - .radius(function(d) { return d.y; }) - .angle(function(d) { return d.x / 180 * Math.PI; }); - - var svg = d3.select("body").append("svg") - .attr("width", diameter) - .attr("height", diameter) - .append("g") - .attr("transform", "translate(" + radius + "," + radius + ")"); - - var link = svg.append("g").selectAll(".link"), - node = svg.append("g").selectAll(".node"), - cycles = {}, highlightCycles, selectedNode; - - function isCyclicLink(l) { - return highlightCycles && - (cycles[l.source.key + "-" + l.target.key] || cycles[l.target.key + "-" + l.source.key]); - } - - function isCyclicPackageLink(l, p) { - var key = l.source.key + "-" + l.target.key, - rKey = l.target.key + "-" + l.source.key; - return isCyclicLink(l) && (p.cycleSegments[key] || p.cycleSegments[rKey]); - } - - function refreshPaths() { - svg.selectAll("path.link").classed("link--cycle", isCyclicLink); - } - - function processCatalog() { - var nodes = cluster.nodes(packageHierarchy(catalog.packages)), - links = packageImports(nodes), - splines = bundle(links); - cycles = catalog.cycleSegments; - - d3.select("input[type=checkbox]").on("change", function() { - highlightCycles = this.checked; - refreshPaths(); - }); - - link = link - .data(splines) - .enter().append("path") - .each(function(d) { d.source = d[0], d.target = d[d.length - 1]; }) - .attr("class", "link") - .classed("link--cycle", isCyclicLink) - .attr("d", function(d, i) { return line(splines[i]); }); - - - node = node - .data(nodes.filter(function(n) { return !n.children; })) - .enter().append("text") - .attr("class", "node") - .attr("dy", ".31em") - .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" + (d.x < 180 ? "" : "rotate(180)"); }) - .style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; }) - .text(function(d) { return d.key; }) - .on("focus", processSelect) - .on("blur", processSelect); - - d3.select("input[type=range]").on("change", function() { - line.tension(this.value / 100); - svg.selectAll("path.link") - .data(splines) - .attr("d", function(d, i) { return line(splines[i]); }); - }); - - d3.select("#packageCount").text(catalog.summary.packages); - d3.select("#sourceCount").text(catalog.summary.sources); - d3.select("#segmentCount").text(catalog.summary.cycleSegments); - d3.select("#cycleCount").text(catalog.summary.cycles); - } - - function processSelect(d) { - if (selectedNode === d) { - deselected(d); - selectedNode = null; - - } else if (selectedNode) { - deselected(selectedNode); - selectedNode = null; - selected(d); - - } else { - selected(d); - selectedNode = d; - } - } - - function selected(d) { - node - .each(function(n) { n.target = n.source = false; }) - .classed("node--focus", function(n) { return n === d; }); - - link - .classed("link--cycle", function(l) { return isCyclicPackageLink(l, d); }) - .classed("link--target", function(l) { if (l.target === d) return l.source.source = true; }) - .classed("link--source", function(l) { if (l.source === d) return l.target.target = true; }) - .filter(function(l) { return l.target === d || l.source === d; }) - .each(function() { this.parentNode.appendChild(this); }); - - node - .classed("node--target", function(n) { return n.target; }) - .classed("node--source", function(n) { return n.source; }); - - d3.select("#psourceCount").text(d.size); - d3.select("#pdependentCount").text(d.imports.length); - d3.select("#psegmentCount").text(d.cycleSegmentCount); - d3.select("#pcycleCount").text(d.cycleCount); - d3.select(".details").classed("shown", function() { return true; }); - } - - function deselected(d) { - link - .classed("link--cycle", isCyclicLink) - .classed("link--target", false) - .classed("link--source", false); - - node - .classed("node--target", false) - .classed("node--source", false) - .classed("node--focus", false); - d3.select(".details").classed("shown", function() { return false; }); - } - - d3.select(self.frameElement).style("height", diameter + "px"); - - // Lazily construct the package hierarchy. - function packageHierarchy(packages) { - var map = {}, cnt = 0; - - // Builds the structure top-down to the specified leaf or until - // another leaf in which case hook this leaf to the same parent - function buildHierarchy(leaf, i) { - var leafName = leaf.name, - node, name, parent = map[""], start = 0; - while (start < leafName.length) { - name = parentName(leafName, start); - node = map[name]; - if (!node) { - node = map[name] = parentNode(name, parent); - parent.children.push(node); - - } else if (node.imports) { - leaf.parent = parent; - parent.children.push(leaf); - break; - } - parent = node; - start = name.length + 1; - } - } - - function parentNode(name, parent) { - return {name: name, parent: parent, key: name, children: []}; - } - - function parentName(leafName, start) { - var i = leafName.indexOf(".", start); - return i > 0 ? leafName.substring(0, i) : leafName; - } - - // First populate all packages as leafs - packages.forEach(function(d) { - map[d.name] = d; - d.key = d.name; - }); - - // Next synthesize the intermediate structure, by-passing any leafs - map[""] = parentNode("", null); - var i = 0; - packages.forEach(function(d) { - buildHierarchy(d, i++); - }); - - return map[""]; - } - - // Return a list of imports for the given array of nodes. - function packageImports(nodes) { - var map = {}, - imports = []; - - // Compute a map from name to node. - nodes.forEach(function(d) { - map[d.name] = d; - }); - - // For each import, construct a link from the source to target node. - nodes.forEach(function(d) { - if (d.imports) d.imports.forEach(function(i) { - imports.push({source: map[d.name], target: map[i]}); - }); - }); - - return imports; - } - - processCatalog(); -</script> -</body> -</html> diff --git a/framework/src/onos/utils/jdvue/src/test/resources/expected.html b/framework/src/onos/utils/jdvue/src/test/resources/expected.html deleted file mode 100644 index a98573e9..00000000 --- a/framework/src/onos/utils/jdvue/src/test/resources/expected.html +++ /dev/null @@ -1,376 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <meta charset="utf-8"> - <title>src/test/resources/catalog</title> - <style> - - .node { - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - fill: #bbb; - } - - .link { - stroke: steelblue; - stroke-opacity: .4; - fill: none; - pointer-events: none; - } - - .node--focus { - font-weight: 700; - fill: #000; - } - - .node:hover { - fill: steelblue; - } - - .node:hover, - .node--source, - .node--target { - font-weight: 700; - } - - .node--source { - fill: #2ca02c; - } - - .node--target { - fill: #d59800; - } - - .link--source, - .link--target { - stroke-opacity: 1; - stroke-width: 3px; - } - - .link--source { - stroke: #d59800; - } - - .link--target { - stroke: #2ca02c; - } - - .link--cycle { - stroke: #ff0000; - } - - .summary { - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - position: fixed; - top: 32px; - right: 32px; - width: 192px; - background-color: #ffffff; - box-shadow: 2px 2px 4px 2px #777777; - padding: 5px; - } - - .details { - display: none; - font: 300 13px "Helvetica Neue", Helvetica, Arial, sans-serif; - position: fixed; - top: 220px; - right: 32px; - width: 192px; - background-color: #ffffff; - box-shadow: 2px 2px 4px 2px #777777; - padding: 5px; - } - - .shown { - display:block; - } - - .stat { - text-align: right; - width: 64px; - } - - .title { - font-size: 16px; - font-weight: bold; - } - - #package { - font-size: 14px; - font-weight: bold; - } - </style> -</head> -<body> - <div class="summary"> - <div class="title">Project src/test/resources/catalog</div> - <table> - <tr> - <td>Sources:</td> - <td id="sourceCount" class="stat"></td> - </tr> - <tr> - <td>Packages:</td> - <td id="packageCount" class="stat"></td> - </tr> - <tr> - <td>Cyclic Segments:</td> - <td id="segmentCount" class="stat"></td> - </tr> - <tr> - <td>Cycles:</td> - <td id="cycleCount" class="stat"></td> - </tr> - </table> - <div><hr size="1"></div> - <div><input type="checkbox"> Highlight cycles</input></div> - <div><input style="width: 95%" type="range" min="0" max="100" value="75"></div> - </div> - <div class="details"> - <div id="package">Package Details</div> - <table> - <tr> - <td>Sources:</td> - <td id="psourceCount" class="stat"></td> - </tr> - <tr> - <td>Dependents:</td> - <td id="pdependentCount" class="stat"></td> - </tr> - <tr> - <td>Cyclic Segments:</td> - <td id="psegmentCount" class="stat"></td> - </tr> - <tr> - <td>Cycles:</td> - <td id="pcycleCount" class="stat"></td> - </tr> - </table> - </div> -<script> -!function(){function n(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function t(n){return null!=n&&!isNaN(n)}function e(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function r(n){return n.length}function u(n){for(var t=1;n*t%1;)t*=10;return t}function i(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function o(){}function a(n){return ia+n in this}function c(n){return n=ia+n,n in this&&delete this[n]}function s(){var n=[];return this.forEach(function(t){n.push(t)}),n}function l(){var n=0;for(var t in this)t.charCodeAt(0)===oa&&++n;return n}function f(){for(var n in this)if(n.charCodeAt(0)===oa)return!1;return!0}function h(){}function g(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function p(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=aa.length;r>e;++e){var u=aa[e]+t;if(u in n)return u}}function v(){}function d(){}function m(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new o;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function y(){Zo.event.preventDefault()}function x(){for(var n,t=Zo.event;n=t.sourceEvent;)t=n;return t}function M(n){for(var t=new d,e=0,r=arguments.length;++e<r;)t[arguments[e]]=m(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=Zo.event;u.target=n,Zo.event=u,t[u.type].apply(e,r)}finally{Zo.event=i}}},t}function _(n){return sa(n,pa),n}function b(n){return"function"==typeof n?n:function(){return la(n,this)}}function w(n){return"function"==typeof n?n:function(){return fa(n,this)}}function S(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=Zo.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function k(n){return n.trim().replace(/\s+/g," ")}function E(n){return new RegExp("(?:^|\\s+)"+Zo.requote(n)+"(?:\\s+|$)","g")}function A(n){return(n+"").trim().split(/^|\s+/)}function C(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=A(n).map(N);var u=n.length;return"function"==typeof t?r:e}function N(n){var t=E(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",k(u+" "+n))):e.setAttribute("class",k(u.replace(t," ")))}}function z(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function L(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function T(n){return"function"==typeof n?n:(n=Zo.ns.qualify(n)).local?function(){return this.ownerDocument.createElementNS(n.space,n.local)}:function(){return this.ownerDocument.createElementNS(this.namespaceURI,n)}}function q(n){return{__data__:n}}function R(n){return function(){return ga(this,n)}}function D(t){return arguments.length||(t=n),function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}}function P(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function U(n){return sa(n,da),n}function j(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function H(){var n=this.__transition__;n&&++n.active}function F(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,Xo(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+Zo.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=O;a>0&&(n=n.substring(0,a));var s=ya.get(n);return s&&(n=s,c=Y),a?t?u:r:t?v:i}function O(n,t){return function(e){var r=Zo.event;Zo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{Zo.event=r}}}function Y(n,t){var e=O(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function I(){var n=".dragsuppress-"+ ++Ma,t="click"+n,e=Zo.select(Wo).on("touchmove"+n,y).on("dragstart"+n,y).on("selectstart"+n,y);if(xa){var r=Bo.style,u=r[xa];r[xa]="none"}return function(i){function o(){e.on(t,null)}e.on(n,null),xa&&(r[xa]=u),i&&(e.on(t,function(){y(),o()},!0),setTimeout(o,0))}}function Z(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>_a&&(Wo.scrollX||Wo.scrollY)){e=Zo.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var u=e[0][0].getScreenCTM();_a=!(u.f||u.e),e.remove()}return _a?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}function V(){return Zo.event.changedTouches[0].identifier}function X(){return Zo.event.target}function $(){return Wo}function B(n){return n>0?1:0>n?-1:0}function W(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function J(n){return n>1?0:-1>n?ba:Math.acos(n)}function G(n){return n>1?Sa:-1>n?-Sa:Math.asin(n)}function K(n){return((n=Math.exp(n))-1/n)/2}function Q(n){return((n=Math.exp(n))+1/n)/2}function nt(n){return((n=Math.exp(2*n))-1)/(n+1)}function tt(n){return(n=Math.sin(n/2))*n}function et(){}function rt(n,t,e){return this instanceof rt?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof rt?new rt(n.h,n.s,n.l):mt(""+n,yt,rt):new rt(n,t,e)}function ut(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new gt(u(n+120),u(n),u(n-120))}function it(n,t,e){return this instanceof it?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof it?new it(n.h,n.c,n.l):n instanceof at?st(n.l,n.a,n.b):st((n=xt((n=Zo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new it(n,t,e)}function ot(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new at(e,Math.cos(n*=Aa)*t,Math.sin(n)*t)}function at(n,t,e){return this instanceof at?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof at?new at(n.l,n.a,n.b):n instanceof it?ot(n.l,n.c,n.h):xt((n=gt(n)).r,n.g,n.b):new at(n,t,e)}function ct(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=lt(u)*ja,r=lt(r)*Ha,i=lt(i)*Fa,new gt(ht(3.2404542*u-1.5371385*r-.4985314*i),ht(-.969266*u+1.8760108*r+.041556*i),ht(.0556434*u-.2040259*r+1.0572252*i))}function st(n,t,e){return n>0?new it(Math.atan2(e,t)*Ca,Math.sqrt(t*t+e*e),n):new it(0/0,0/0,n)}function lt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function ft(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function ht(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function gt(n,t,e){return this instanceof gt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof gt?new gt(n.r,n.g,n.b):mt(""+n,gt,ut):new gt(n,t,e)}function pt(n){return new gt(n>>16,255&n>>8,255&n)}function vt(n){return pt(n)+""}function dt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function mt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(_t(u[0]),_t(u[1]),_t(u[2]))}return(i=Ia.get(n))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.substring(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function yt(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new rt(r,u,c)}function xt(n,t,e){n=Mt(n),t=Mt(t),e=Mt(e);var r=ft((.4124564*n+.3575761*t+.1804375*e)/ja),u=ft((.2126729*n+.7151522*t+.072175*e)/Ha),i=ft((.0193339*n+.119192*t+.9503041*e)/Fa);return at(116*u-16,500*(r-u),200*(u-i))}function Mt(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function _t(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function bt(n){return"function"==typeof n?n:function(){return n}}function wt(n){return n}function St(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),kt(t,e,n,r)}}function kt(n,t,e,r){function u(){var n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return o.error.call(i,r),void 0}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=Zo.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,s=null;return!Wo.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=Zo.event;Zo.event=n;try{o.progress.call(i,c)}finally{Zo.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(s=n,i):s},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(Xo(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var l in a)c.setRequestHeader(l,a[l]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=s&&(c.responseType=s),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},Zo.rebind(i,o,"on"),null==r?i:i.get(Et(r))}function Et(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function At(){var n=Ct(),t=Nt()-n;t>24?(isFinite(t)&&(clearTimeout($a),$a=setTimeout(At,t)),Xa=0):(Xa=1,Wa(At))}function Ct(){var n=Date.now();for(Ba=Za;Ba;)n>=Ba.t&&(Ba.f=Ba.c(n-Ba.t)),Ba=Ba.n;return n}function Nt(){for(var n,t=Za,e=1/0;t;)t.f?t=n?n.n=t.n:Za=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Va=n,e}function zt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Lt(n,t){var e=Math.pow(10,3*ua(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Tt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r?function(n){for(var t=n.length,u=[],i=0,o=r[0];t>0&&o>0;)u.push(n.substring(t-=o,t+o)),o=r[i=(i+1)%r.length];return u.reverse().join(e)}:wt;return function(n){var e=Ga.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"",c=e[4]||"",s=e[5],l=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1;switch(h&&(h=+h.substring(1)),(s||"0"===r&&"="===o)&&(s=r="0",o="=",f&&(l-=Math.floor((l-1)/4))),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=Ka.get(g)||qt;var y=s&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):a;if(0>p){var c=Zo.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x=n.lastIndexOf("."),M=0>x?n:n.substring(0,x),_=0>x?"":t+n.substring(x+1);!s&&f&&(M=i(M));var b=v.length+M.length+_.length+(y?0:u.length),w=l>b?new Array(b=l-b+1).join(r):"";return y&&(M=i(w+M)),u+=v,n=M+_,("<"===o?u+n+w:">"===o?w+u+n:"^"===o?w.substring(0,b>>=1)+u+n+w.substring(b):u+(y?n:w+n))+e}}}function qt(n){return n+""}function Rt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Dt(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new nc(e-1)),1),e}function i(n,e){return t(n=new nc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{nc=Rt;var r=new Rt;return r._=n,o(r,t,e)}finally{nc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Pt(n);return c.floor=c,c.round=Pt(r),c.ceil=Pt(u),c.offset=Pt(i),c.range=a,n}function Pt(n){return function(t,e){try{nc=Rt;var r=new Rt;return r._=t,n(r,e)._}finally{nc=Date}}}function Ut(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.substring(c,a)),null!=(u=ec[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=C[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.substring(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&nc!==Rt,o=new(i?Rt:nc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+Math.floor(r.Z/100),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,s=e.length;c>a;){if(r>=s)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=N[o in ec?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){b.lastIndex=0;var r=b.exec(t.substring(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){M.lastIndex=0;var r=M.exec(t.substring(e));return r?(n.w=_.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.substring(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.substring(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,C.c.toString(),t,r)}function c(n,t,r){return e(n,C.x.toString(),t,r)}function s(n,t,r){return e(n,C.X.toString(),t,r)}function l(n,t,e){var r=x.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{nc=Rt;var t=new nc;return t._=n,r(t)}finally{nc=Date}}var r=t(n);return e.parse=function(n){try{nc=Rt;var t=r.parse(n);return t&&t._}finally{nc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=re;var x=Zo.map(),M=Ht(v),_=Ft(v),b=Ht(d),w=Ft(d),S=Ht(m),k=Ft(m),E=Ht(y),A=Ft(y);p.forEach(function(n,t){x.set(n.toLowerCase(),t)});var C={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return jt(n.getDate(),t,2)},e:function(n,t){return jt(n.getDate(),t,2)},H:function(n,t){return jt(n.getHours(),t,2)},I:function(n,t){return jt(n.getHours()%12||12,t,2)},j:function(n,t){return jt(1+Qa.dayOfYear(n),t,3)},L:function(n,t){return jt(n.getMilliseconds(),t,3)},m:function(n,t){return jt(n.getMonth()+1,t,2)},M:function(n,t){return jt(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return jt(n.getSeconds(),t,2)},U:function(n,t){return jt(Qa.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return jt(Qa.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return jt(n.getFullYear()%100,t,2)},Y:function(n,t){return jt(n.getFullYear()%1e4,t,4)},Z:te,"%":function(){return"%"}},N={a:r,A:u,b:i,B:o,c:a,d:Wt,e:Wt,H:Gt,I:Gt,j:Jt,L:ne,m:Bt,M:Kt,p:l,S:Qt,U:Yt,w:Ot,W:It,x:c,X:s,y:Vt,Y:Zt,Z:Xt,"%":ee};return t}function jt(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Ht(n){return new RegExp("^(?:"+n.map(Zo.requote).join("|")+")","i")}function Ft(n){for(var t=new o,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Ot(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Yt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e));return r?(n.U=+r[0],e+r[0].length):-1}function It(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e));return r?(n.W=+r[0],e+r[0].length):-1}function Zt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Vt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.y=$t(+r[0]),e+r[0].length):-1}function Xt(n,t,e){return/^[+-]\d{4}$/.test(t=t.substring(e,e+5))?(n.Z=-t,e+5):-1}function $t(n){return n+(n>68?1900:2e3)}function Bt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Wt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function Jt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function Gt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function Kt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function Qt(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ne(n,t,e){rc.lastIndex=0;var r=rc.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function te(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(ua(t)/60),u=ua(t)%60;return e+jt(r,"0",2)+jt(u,"0",2)}function ee(n,t,e){uc.lastIndex=0;var r=uc.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function re(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ue(){}function ie(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function oe(n,t){n&&cc.hasOwnProperty(n.type)&&cc[n.type](n,t)}function ae(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function ce(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)ae(n[e],t,1);t.polygonEnd()}function se(){function n(n,t){n*=Aa,t=t*Aa/2+ba/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),s=Math.sin(t),l=i*s,f=u*c+l*Math.cos(a),h=l*o*Math.sin(a);lc.add(Math.atan2(h,f)),r=n,u=c,i=s}var t,e,r,u,i;fc.point=function(o,a){fc.point=n,r=(t=o)*Aa,u=Math.cos(a=(e=a)*Aa/2+ba/4),i=Math.sin(a)},fc.lineEnd=function(){n(t,e)}}function le(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function fe(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function he(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function ge(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function pe(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function ve(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function de(n){return[Math.atan2(n[1],n[0]),G(n[2])]}function me(n,t){return ua(n[0]-t[0])<ka&&ua(n[1]-t[1])<ka}function ye(n,t){n*=Aa;var e=Math.cos(t*=Aa);xe(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function xe(n,t,e){++hc,pc+=(n-pc)/hc,vc+=(t-vc)/hc,dc+=(e-dc)/hc}function Me(){function n(n,u){n*=Aa;var i=Math.cos(u*=Aa),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),s=Math.atan2(Math.sqrt((s=e*c-r*a)*s+(s=r*o-t*c)*s+(s=t*a-e*o)*s),t*o+e*a+r*c);gc+=s,mc+=s*(t+(t=o)),yc+=s*(e+(e=a)),xc+=s*(r+(r=c)),xe(t,e,r)}var t,e,r;wc.point=function(u,i){u*=Aa;var o=Math.cos(i*=Aa);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),wc.point=n,xe(t,e,r)}}function _e(){wc.point=ye}function be(){function n(n,t){n*=Aa;var e=Math.cos(t*=Aa),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),s=u*c-i*a,l=i*o-r*c,f=r*a-u*o,h=Math.sqrt(s*s+l*l+f*f),g=r*o+u*a+i*c,p=h&&-J(g)/h,v=Math.atan2(h,g);Mc+=p*s,_c+=p*l,bc+=p*f,gc+=v,mc+=v*(r+(r=o)),yc+=v*(u+(u=a)),xc+=v*(i+(i=c)),xe(r,u,i)}var t,e,r,u,i;wc.point=function(o,a){t=o,e=a,wc.point=n,o*=Aa;var c=Math.cos(a*=Aa);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),xe(r,u,i)},wc.lineEnd=function(){n(t,e),wc.lineEnd=_e,wc.point=ye}}function we(){return!0}function Se(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(me(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return u.lineEnd(),void 0}var c=new Ee(e,n,null,!0),s=new Ee(e,null,c,!1);c.o=s,i.push(c),o.push(s),c=new Ee(r,n,null,!1),s=new Ee(r,null,c,!0),c.o=s,i.push(c),o.push(s)}}),o.sort(t),ke(i),ke(o),i.length){for(var a=0,c=e,s=o.length;s>a;++a)o[a].e=c=!c;for(var l,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;l=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,s=l.length;s>a;++a)u.point((f=l[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){l=g.p.z;for(var a=l.length-1;a>=0;--a)u.point((f=l[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,l=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ke(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function Ee(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Ae(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function s(){y.point=o,d.lineEnd()}function l(n,t){v.push([n,t]);var e=u(n,t);M.point(e[0],e[1])}function f(){M.lineStart(),v=[]}function h(){l(v[0][0],v[0][1]),M.lineEnd();var n,t=M.clean(),e=x.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(_||(i.polygonStart(),_=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Ce))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:s,polygonStart:function(){y.point=l,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=s,g=Zo.merge(g);var n=Le(m,p);g.length?(_||(i.polygonStart(),_=!0),Se(g,ze,n,e,i)):n&&(_||(i.polygonStart(),_=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),_&&(i.polygonEnd(),_=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},x=Ne(),M=t(x),_=!1;return y}}function Ce(n){return n.length>1}function Ne(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:v,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function ze(n,t){return((n=n.x)[0]<0?n[1]-Sa-ka:Sa-n[1])-((t=t.x)[0]<0?t[1]-Sa-ka:Sa-t[1])}function Le(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;lc.reset();for(var a=0,c=t.length;c>a;++a){var s=t[a],l=s.length;if(l)for(var f=s[0],h=f[0],g=f[1]/2+ba/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===l&&(d=0),n=s[d];var m=n[0],y=n[1]/2+ba/4,x=Math.sin(y),M=Math.cos(y),_=m-h,b=_>=0?1:-1,w=b*_,S=w>ba,k=p*x;if(lc.add(Math.atan2(k*b*Math.sin(w),v*M+k*Math.cos(w))),i+=S?_+b*wa:_,S^h>=e^m>=e){var E=he(le(f),le(n));ve(E);var A=he(u,E);ve(A);var C=(S^_>=0?-1:1)*G(A[2]);(r>C||r===C&&(E[0]||E[1]))&&(o+=S^_>=0?1:-1)}if(!d++)break;h=m,p=x,v=M,f=n}}return(-ka>i||ka>i&&0>lc)^1&o}function Te(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?ba:-ba,c=ua(i-e);ua(c-ba)<ka?(n.point(e,r=(r+o)/2>0?Sa:-Sa),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=ba&&(ua(e-u)<ka&&(e-=u*ka),ua(i-a)<ka&&(i-=a*ka),r=qe(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function qe(n,t,e,r){var u,i,o=Math.sin(n-e);return ua(o)>ka?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function Re(n,t,e,r){var u;if(null==n)u=e*Sa,r.point(-ba,u),r.point(0,u),r.point(ba,u),r.point(ba,0),r.point(ba,-u),r.point(0,-u),r.point(-ba,-u),r.point(-ba,0),r.point(-ba,u);else if(ua(n[0]-t[0])>ka){var i=n[0]<t[0]?ba:-ba;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function De(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,s,l;return{lineStart:function(){s=c=!1,l=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?ba:-ba),h):0;if(!e&&(s=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(me(e,g)||me(p,g))&&(p[0]+=ka,p[1]+=ka,v=t(p[0],p[1]))),v!==c)l=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(l=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&me(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return l|(s&&c)<<1}}}function r(n,t,e){var r=le(n),u=le(t),o=[1,0,0],a=he(r,u),c=fe(a,a),s=a[0],l=c-s*s;if(!l)return!e&&n;var f=i*c/l,h=-i*s/l,g=he(o,a),p=pe(o,f),v=pe(a,h);ge(p,v);var d=g,m=fe(p,d),y=fe(d,d),x=m*m-y*(fe(p,p)-1);if(!(0>x)){var M=Math.sqrt(x),_=pe(d,(-m-M)/y);if(ge(_,p),_=de(_),!e)return _;var b,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(b=w,w=S,S=b);var A=S-w,C=ua(A-ba)<ka,N=C||ka>A;if(!C&&k>E&&(b=k,k=E,E=b),N?C?k+E>0^_[1]<(ua(_[0]-w)<ka?k:E):k<=_[1]&&_[1]<=E:A>ba^(w<=_[0]&&_[0]<=S)){var z=pe(d,(-m+M)/y);return ge(z,p),[_,de(z)]}}}function u(t,e){var r=o?n:ba-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ua(i)>ka,c=sr(n,6*Aa);return Ae(t,e,c,o?[0,-n]:[-ba,n-ba])}function Pe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,s=o.y,l=a.x,f=a.y,h=0,g=1,p=l-c,v=f-s;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-s,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-s,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:s+h*v}),1>g&&(u.b={x:c+g*p,y:s+g*v}),u}}}}}}function Ue(n,t,e,r){function u(r,u){return ua(r[0]-n)<ka?u>0?0:3:ua(r[0]-e)<ka?u>0?2:1:ua(r[1]-t)<ka?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,s=a[0];c>o;++o)i=a[o],s[1]<=r?i[1]>r&&W(s,i,n)>0&&++t:i[1]<=r&&W(s,i,n)<0&&--t,s=i;return 0!==t}function s(i,a,c,s){var l=0,f=0;if(null==i||(l=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do s.point(0===l||3===l?n:e,l>1?r:t);while((l=(l+c+4)%4)!==f)}else s.point(a[0],a[1])}function l(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){l(n,t)&&a.point(n,t)}function h(){N.point=p,d&&d.push(m=[]),S=!0,w=!1,_=b=0/0}function g(){v&&(p(y,x),M&&w&&A.rejoin(),v.push(A.buffer())),N.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-kc,Math.min(kc,n)),t=Math.max(-kc,Math.min(kc,t));var e=l(n,t);if(d&&m.push([n,t]),S)y=n,x=t,M=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:_,y:b},b:{x:n,y:t}};C(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}_=n,b=t,w=e}var v,d,m,y,x,M,_,b,w,S,k,E=a,A=Ne(),C=Pe(n,t,e,r),N={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=Zo.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),s(null,null,1,a),a.lineEnd()),u&&Se(v,i,t,s,a),a.polygonEnd()),v=d=m=null}};return N}}function je(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function He(n){var t=0,e=ba/3,r=tr(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*ba/180,e=n[1]*ba/180):[180*(t/ba),180*(e/ba)]},u}function Fe(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,G((i-(n*n+e*e)*u*u)/(2*u))]},e}function Oe(){function n(n,t){Ac+=u*n-r*t,r=n,u=t}var t,e,r,u;Tc.point=function(i,o){Tc.point=n,t=r=i,e=u=o},Tc.lineEnd=function(){n(t,e)}}function Ye(n,t){Cc>n&&(Cc=n),n>zc&&(zc=n),Nc>t&&(Nc=t),t>Lc&&(Lc=t)}function Ie(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Ze(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Ze(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Ze(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Ve(n,t){pc+=n,vc+=t,++dc}function Xe(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);mc+=o*(t+n)/2,yc+=o*(e+r)/2,xc+=o,Ve(t=n,e=r)}var t,e;Rc.point=function(r,u){Rc.point=n,Ve(t=r,e=u)}}function $e(){Rc.point=Ve}function Be(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);mc+=o*(r+n)/2,yc+=o*(u+t)/2,xc+=o,o=u*n-r*t,Mc+=o*(r+n),_c+=o*(u+t),bc+=3*o,Ve(r=n,u=t)}var t,e,r,u;Rc.point=function(i,o){Rc.point=n,Ve(t=r=i,e=u=o)},Rc.lineEnd=function(){n(t,e)}}function We(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,wa)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:v};return a}function Je(n){function t(n){return(a?r:e)(n)}function e(t){return Qe(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){x=0/0,S.point=i,t.lineStart()}function i(e,r){var i=le([e,r]),o=n(e,r);u(x,M,y,_,b,w,x=o[0],M=o[1],y=e,_=i[0],b=i[1],w=i[2],a,t),t.point(x,M)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=s,S.lineEnd=l}function s(n,t){i(f=n,h=t),g=x,p=M,v=_,d=b,m=w,S.point=i}function l(){u(x,M,y,_,b,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,x,M,_,b,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,s,l,f,h,g,p,v,d,m){var y=l-t,x=f-e,M=y*y+x*x;if(M>4*i&&d--){var _=a+g,b=c+p,w=s+v,S=Math.sqrt(_*_+b*b+w*w),k=Math.asin(w/=S),E=ua(ua(w)-1)<ka||ua(r-h)<ka?(r+h)/2:Math.atan2(b,_),A=n(E,k),C=A[0],N=A[1],z=C-t,L=N-e,T=x*z-y*L;(T*T/M>i||ua((y*z+x*L)/M-.5)>.3||o>a*g+c*p+s*v)&&(u(t,e,r,a,c,s,C,N,E,_/=S,b/=S,w,d,m),m.point(C,N),u(C,N,E,_,b,w,l,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Aa),a=16; - return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function Ge(n){var t=Je(function(t,e){return n([t*Ca,e*Ca])});return function(n){return er(t(n))}}function Ke(n){this.stream=n}function Qe(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function nr(n){return tr(function(){return n})()}function tr(n){function t(n){return n=a(n[0]*Aa,n[1]*Aa),[n[0]*h+c,s-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(s-n[1])/h),n&&[n[0]*Ca,n[1]*Ca]}function r(){a=je(o=ir(m,y,x),i);var n=i(v,d);return c=g-n[0]*h,s=p+n[1]*h,u()}function u(){return l&&(l.valid=!1,l=null),t}var i,o,a,c,s,l,f=Je(function(n,t){return n=i(n,t),[n[0]*h+c,s-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,y=0,x=0,M=Sc,_=wt,b=null,w=null;return t.stream=function(n){return l&&(l.valid=!1),l=er(M(o,f(_(n)))),l.valid=!0,l},t.clipAngle=function(n){return arguments.length?(M=null==n?(b=n,Sc):De((b=+n)*Aa),u()):b},t.clipExtent=function(n){return arguments.length?(w=n,_=n?Ue(n[0][0],n[0][1],n[1][0],n[1][1]):wt,u()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Aa,d=n[1]%360*Aa,r()):[v*Ca,d*Ca]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Aa,y=n[1]%360*Aa,x=n.length>2?n[2]%360*Aa:0,r()):[m*Ca,y*Ca,x*Ca]},Zo.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function er(n){return Qe(n,function(t,e){n.point(t*Aa,e*Aa)})}function rr(n,t){return[n,t]}function ur(n,t){return[n>ba?n-wa:-ba>n?n+wa:n,t]}function ir(n,t,e){return n?t||e?je(ar(n),cr(t,e)):ar(n):t||e?cr(t,e):ur}function or(n){return function(t,e){return t+=n,[t>ba?t-wa:-ba>t?t+wa:t,e]}}function ar(n){var t=or(n);return t.invert=or(-n),t}function cr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*r+a*u;return[Math.atan2(c*i-l*o,a*r-s*u),G(l*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*i-c*o;return[Math.atan2(c*i+s*o,a*r+l*u),G(l*r-a*u)]},e}function sr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=lr(e,u),i=lr(e,i),(o>0?i>u:u>i)&&(u+=o*wa)):(u=n+o*wa,i=n-.5*c);for(var s,l=u;o>0?l>i:i>l;l-=c)a.point((s=de([e,-r*Math.cos(l),-r*Math.sin(l)]))[0],s[1])}}function lr(n,t){var e=le(t);e[0]-=n,ve(e);var r=J(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-ka)%(2*Math.PI)}function fr(n,t,e){var r=Zo.range(n,t-ka,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function hr(n,t,e){var r=Zo.range(n,t-ka,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function gr(n){return n.source}function pr(n){return n.target}function vr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),s=u*Math.sin(n),l=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(tt(r-t)+u*o*tt(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*l,u=e*s+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Ca,Math.atan2(o,Math.sqrt(r*r+u*u))*Ca]}:function(){return[n*Ca,t*Ca]};return p.distance=h,p}function dr(){function n(n,u){var i=Math.sin(u*=Aa),o=Math.cos(u),a=ua((n*=Aa)-t),c=Math.cos(a);Dc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Pc.point=function(u,i){t=u*Aa,e=Math.sin(i*=Aa),r=Math.cos(i),Pc.point=n},Pc.lineEnd=function(){Pc.point=Pc.lineEnd=v}}function mr(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function yr(n,t){function e(n,t){o>0?-Sa+ka>t&&(t=-Sa+ka):t>Sa-ka&&(t=Sa-ka);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(ba/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=B(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Sa]},e):Mr}function xr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ua(u)<ka?rr:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-B(u)*Math.sqrt(n*n+e*e)]},e)}function Mr(n,t){return[n,Math.log(Math.tan(ba/4+t/2))]}function _r(n){var t,e=nr(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=ba*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function br(n,t){return[Math.log(Math.tan(ba/4+t/2)),-n]}function wr(n){return n[0]}function Sr(n){return n[1]}function kr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&W(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function Er(n,t){return n[0]-t[0]||n[1]-t[1]}function Ar(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Cr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],s=e[1],l=t[1]-c,f=r[1]-s,h=(a*(c-s)-f*(u-i))/(f*o-a*l);return[u+h*o,c+h*l]}function Nr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function zr(){Gr(this),this.edge=this.site=this.circle=null}function Lr(n){var t=Bc.pop()||new zr;return t.site=n,t}function Tr(n){Yr(n),Vc.remove(n),Bc.push(n),Gr(n)}function qr(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Tr(n);for(var c=i;c.circle&&ua(e-c.circle.x)<ka&&ua(r-c.circle.cy)<ka;)i=c.P,a.unshift(c),Tr(c),c=i;a.unshift(c),Yr(c);for(var s=o;s.circle&&ua(e-s.circle.x)<ka&&ua(r-s.circle.cy)<ka;)o=s.N,a.push(s),Tr(s),s=o;a.push(s),Yr(s);var l,f=a.length;for(l=1;f>l;++l)s=a[l],c=a[l-1],Br(s.edge,c.site,s.site,u);c=a[0],s=a[f-1],s.edge=Xr(c.site,s.site,null,u),Or(c),Or(s)}function Rr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Vc._;a;)if(r=Dr(a,o)-i,r>ka)a=a.L;else{if(u=i-Pr(a,o),!(u>ka)){r>-ka?(t=a.P,e=a):u>-ka?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Lr(n);if(Vc.insert(t,c),t||e){if(t===e)return Yr(t),e=Lr(t.site),Vc.insert(c,e),c.edge=e.edge=Xr(t.site,c.site),Or(t),Or(e),void 0;if(!e)return c.edge=Xr(t.site,c.site),void 0;Yr(t),Yr(e);var s=t.site,l=s.x,f=s.y,h=n.x-l,g=n.y-f,p=e.site,v=p.x-l,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,x=v*v+d*d,M={x:(d*y-g*x)/m+l,y:(h*x-v*y)/m+f};Br(e.edge,s,p,M),c.edge=Xr(s,n,null,M),e.edge=Xr(n,p,null,M),Or(t),Or(e)}}function Dr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,s=c-t;if(!s)return a;var l=a-r,f=1/i-1/s,h=l/s;return f?(-h+Math.sqrt(h*h-2*f*(l*l/(-2*s)-c+s/2+u-i/2)))/f+r:(r+a)/2}function Pr(n,t){var e=n.N;if(e)return Dr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ur(n){this.site=n,this.edges=[]}function jr(n){for(var t,e,r,u,i,o,a,c,s,l,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Zc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)l=a[o].end(),r=l.x,u=l.y,s=a[++o%c].start(),t=s.x,e=s.y,(ua(r-t)>ka||ua(u-e)>ka)&&(a.splice(o,0,new Wr($r(i.site,l,ua(r-f)<ka&&p-u>ka?{x:f,y:ua(t-f)<ka?e:p}:ua(u-p)<ka&&h-r>ka?{x:ua(e-p)<ka?t:h,y:p}:ua(r-h)<ka&&u-g>ka?{x:h,y:ua(t-h)<ka?e:g}:ua(u-g)<ka&&r-f>ka?{x:ua(e-g)<ka?t:f,y:g}:null),i.site,null)),++c)}function Hr(n,t){return t.angle-n.angle}function Fr(){Gr(this),this.x=this.y=this.arc=this.site=this.cy=null}function Or(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,s=r.y-a,l=i.x-o,f=i.y-a,h=2*(c*f-s*l);if(!(h>=-Ea)){var g=c*c+s*s,p=l*l+f*f,v=(f*g-s*p)/h,d=(c*p-l*g)/h,f=d+a,m=Wc.pop()||new Fr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,x=$c._;x;)if(m.y<x.y||m.y===x.y&&m.x<=x.x){if(!x.L){y=x.P;break}x=x.L}else{if(!x.R){y=x;break}x=x.R}$c.insert(y,m),y||(Xc=m)}}}}function Yr(n){var t=n.circle;t&&(t.P||(Xc=t.N),$c.remove(t),Wc.push(t),Gr(t),n.circle=null)}function Ir(n){for(var t,e=Ic,r=Pe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Zr(t,n)||!r(t)||ua(t.a.x-t.b.x)<ka&&ua(t.a.y-t.b.y)<ka)&&(t.a=t.b=null,e.splice(u,1))}function Zr(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],s=t[1][1],l=n.l,f=n.r,h=l.x,g=l.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=s)return}else i={x:d,y:c};e={x:d,y:s}}else{if(i){if(i.y<c)return}else i={x:d,y:s};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=s)return}else i={x:(c-u)/r,y:c};e={x:(s-u)/r,y:s}}else{if(i){if(i.y<c)return}else i={x:(s-u)/r,y:s};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Vr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Xr(n,t,e,r){var u=new Vr(n,t);return Ic.push(u),e&&Br(u,n,t,e),r&&Br(u,t,n,r),Zc[n.i].edges.push(new Wr(u,n,t)),Zc[t.i].edges.push(new Wr(u,t,n)),u}function $r(n,t,e){var r=new Vr(n,null);return r.a=t,r.b=e,Ic.push(r),r}function Br(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Wr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function Jr(){this._=null}function Gr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function Kr(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Qr(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function nu(n){for(;n.L;)n=n.L;return n}function tu(n,t){var e,r,u,i=n.sort(eu).pop();for(Ic=[],Zc=new Array(n.length),Vc=new Jr,$c=new Jr;;)if(u=Xc,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Zc[i.i]=new Ur(i),Rr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;qr(u.arc)}t&&(Ir(t),jr(t));var o={cells:Zc,edges:Ic};return Vc=$c=Ic=Zc=null,o}function eu(n,t){return t.y-n.y||t.x-n.x}function ru(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function uu(n){return n.x}function iu(n){return n.y}function ou(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function au(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&au(n,c[0],e,r,o,a),c[1]&&au(n,c[1],o,r,u,a),c[2]&&au(n,c[2],e,a,o,i),c[3]&&au(n,c[3],o,a,u,i)}}function cu(n,t){n=Zo.rgb(n),t=Zo.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+dt(Math.round(e+i*n))+dt(Math.round(r+o*n))+dt(Math.round(u+a*n))}}function su(n,t){var e,r={},u={};for(e in n)e in t?r[e]=hu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function lu(n,t){return t-=n=+n,function(e){return n+t*e}}function fu(n,t){var e,r,u,i=Gc.lastIndex=Kc.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=Gc.exec(n))&&(r=Kc.exec(t));)(u=r.index)>i&&(u=t.substring(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:lu(e,r)})),i=Kc.lastIndex;return i<t.length&&(u=t.substring(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function hu(n,t){for(var e,r=Zo.interpolators.length;--r>=0&&!(e=Zo.interpolators[r](n,t)););return e}function gu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(hu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function pu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function vu(n){return function(t){return 1-n(1-t)}}function du(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function mu(n){return n*n}function yu(n){return n*n*n}function xu(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Mu(n){return function(t){return Math.pow(t,n)}}function _u(n){return 1-Math.cos(n*Sa)}function bu(n){return Math.pow(2,10*(n-1))}function wu(n){return 1-Math.sqrt(1-n*n)}function Su(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/wa*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*wa/t)}}function ku(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Eu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Au(n,t){n=Zo.hcl(n),t=Zo.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ot(e+i*n,r+o*n,u+a*n)+""}}function Cu(n,t){n=Zo.hsl(n),t=Zo.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ut(e+i*n,r+o*n,u+a*n)+""}}function Nu(n,t){n=Zo.lab(n),t=Zo.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function zu(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Lu(n){var t=[n.a,n.b],e=[n.c,n.d],r=qu(t),u=Tu(t,e),i=qu(Ru(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Ca,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Ca:0}function Tu(n,t){return n[0]*t[0]+n[1]*t[1]}function qu(n){var t=Math.sqrt(Tu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Ru(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Du(n,t){var e,r=[],u=[],i=Zo.transform(n),o=Zo.transform(t),a=i.translate,c=o.translate,s=i.rotate,l=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:lu(a[0],c[0])},{i:3,x:lu(a[1],c[1])})):c[0]||c[1]?r.push("translate("+c+")"):r.push(""),s!=l?(s-l>180?l+=360:l-s>180&&(s+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:lu(s,l)})):l&&r.push(r.pop()+"rotate("+l+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:lu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:lu(g[0],p[0])},{i:e-2,x:lu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Pu(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return(e-n)*t}}function Uu(n,t){return t=t-(n=+n)?1/(t-n):0,function(e){return Math.max(0,Math.min(1,(e-n)*t))}}function ju(n){for(var t=n.source,e=n.target,r=Fu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Hu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Fu(n,t){if(n===t)return n;for(var e=Hu(n),r=Hu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Ou(n){n.fixed|=2}function Yu(n){n.fixed&=-7}function Iu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Zu(n){n.fixed&=-5}function Vu(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Vu(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var s=t*e[n.point.index];n.charge+=n.pointCharge=s,r+=s*n.point.x,u+=s*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Xu(n,t){return Zo.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=Ku,n}function $u(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Bu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function Wu(n){return n.children}function Ju(n){return n.value}function Gu(n,t){return t.value-n.value}function Ku(n){return Zo.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function Qu(n){return n.x}function ni(n){return n.y}function ti(n,t,e){n.y0=t,n.y=e}function ei(n){return Zo.range(n.length)}function ri(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function ui(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function ii(n){return n.reduce(oi,0)}function oi(n,t){return n+t[1]}function ai(n,t){return ci(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function ci(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function si(n){return[Zo.min(n),Zo.max(n)]}function li(n,t){return n.value-t.value}function fi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function hi(n,t){n._pack_next=t,t._pack_prev=n}function gi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function pi(n){function t(n){l=Math.min(n.x-n.r,l),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(s=e.length)){var e,r,u,i,o,a,c,s,l=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(vi),r=e[0],r.x=-r.r,r.y=0,t(r),s>1&&(u=e[1],u.x=u.r,u.y=0,t(u),s>2))for(i=e[2],yi(r,u,i),t(i),fi(r,i),r._pack_prev=i,fi(i,u),u=r._pack_next,o=3;s>o;o++){yi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(gi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!gi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?hi(r,u=a):hi(r=c,u),o--):(fi(r,i),u=i,t(i))}var m=(l+f)/2,y=(h+g)/2,x=0;for(o=0;s>o;o++)i=e[o],i.x-=m,i.y-=y,x=Math.max(x,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=x,e.forEach(di)}}function vi(n){n._pack_next=n._pack_prev=n}function di(n){delete n._pack_next,delete n._pack_prev}function mi(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)mi(u[i],t,e,r)}function yi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),s=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+s*i,e.y=n.y+c*i-s*u}else e.x=n.x+r,e.y=n.y}function xi(n,t){return n.parent==t.parent?1:2}function Mi(n){var t=n.children;return t.length?t[0]:n.t}function _i(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function bi(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function wi(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Si(n,t,e){return n.a.parent===t.parent?n.a:e}function ki(n){return 1+Zo.max(n,function(n){return n.y})}function Ei(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Ai(n){var t=n.children;return t&&t.length?Ai(t[0]):n}function Ci(n){var t,e=n.children;return e&&(t=e.length)?Ci(e[t-1]):n}function Ni(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function zi(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Li(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ti(n){return n.rangeExtent?n.rangeExtent():Li(n.range())}function qi(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Ri(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Di(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ss}function Pi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=Zo.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ui(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Pi:qi,c=r?Uu:Pu;return o=u(n,t,c,e),a=u(t,n,c,hu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(zu)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Oi(n,t)},i.tickFormat=function(t,e){return Yi(n,t,e)},i.nice=function(t){return Hi(n,t),u()},i.copy=function(){return Ui(n,t,e,r)},u()}function ji(n,t){return Zo.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Hi(n,t){return Ri(n,Di(Fi(n,t)[2]))}function Fi(n,t){null==t&&(t=10);var e=Li(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Oi(n,t){return Zo.range.apply(Zo,Fi(n,t))}function Yi(n,t,e){var r=Fi(n,t);if(e){var u=Ga.exec(e);if(u.shift(),"s"===u[8]){var i=Zo.formatPrefix(Math.max(ua(r[0]),ua(r[1])));return u[7]||(u[7]="."+Ii(i.scale(r[2]))),u[8]="f",e=Zo.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Zi(u[8],r)),e=u.join("")}else e=",."+Ii(r[2])+"f";return Zo.format(e)}function Ii(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Zi(n,t){var e=Ii(t[2]);return n in ls?Math.abs(e-Ii(Math.max(ua(t[0]),ua(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Vi(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Ri(r.map(u),e?Math:hs);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Li(r),o=[],a=n[0],c=n[1],s=Math.floor(u(a)),l=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(l-s)){if(e){for(;l>s;s++)for(var h=1;f>h;h++)o.push(i(s)*h);o.push(i(s))}else for(o.push(i(s));s++<l;)for(var h=f-1;h>0;h--)o.push(i(s)*h);for(s=0;o[s]<a;s++);for(l=o.length;o[l-1]>c;l--);o=o.slice(s,l)}return o},o.tickFormat=function(n,t){if(!arguments.length)return fs;arguments.length<2?t=fs:"function"!=typeof t&&(t=Zo.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Vi(n.copy(),t,e,r)},ji(o,n)}function Xi(n,t,e){function r(t){return n(u(t))}var u=$i(t),i=$i(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Oi(e,n)},r.tickFormat=function(n,t){return Yi(e,n,t)},r.nice=function(n){return r.domain(Hi(e,n))},r.exponent=function(o){return arguments.length?(u=$i(t=o),i=$i(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Xi(n.copy(),t,e)},ji(r,n)}function $i(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Bi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return Zo.range(n.length).map(function(n){return t+e*n})}var u,i,a;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new o;for(var i,a=-1,c=r.length;++a<c;)u.has(i=r[a])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,a=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,o){arguments.length<2&&(o=0);var c=u[0],s=u[1],l=(s-c)/(Math.max(1,n.length-1)+o);return i=r(n.length<2?(c+s)/2:c+l*o/2,l),a=0,t={t:"rangePoints",a:arguments},e},e.rangeBands=function(u,o,c){arguments.length<2&&(o=0),arguments.length<3&&(c=o);var s=u[1]<u[0],l=u[s-0],f=u[1-s],h=(f-l)/(n.length-o+2*c);return i=r(l+h*c,h),s&&i.reverse(),a=h*(1-o),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,o,c){arguments.length<2&&(o=0),arguments.length<3&&(c=o);var s=u[1]<u[0],l=u[s-0],f=u[1-s],h=Math.floor((f-l)/(n.length-o+2*c)),g=f-l-(n.length-o)*h;return i=r(l+Math.round(g/2),h),s&&i.reverse(),a=Math.round(h*(1-o)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return a},e.rangeExtent=function(){return Li(t.a[0])},e.copy=function(){return Bi(n,t)},e.domain(n)}function Wi(e,r){function u(){var n=0,t=r.length;for(o=[];++n<t;)o[n-1]=Zo.quantile(e,n/t);return i}function i(n){return isNaN(n=+n)?void 0:r[Zo.bisect(o,n)]}var o;return i.domain=function(r){return arguments.length?(e=r.filter(t).sort(n),u()):e},i.range=function(n){return arguments.length?(r=n,u()):r},i.quantiles=function(){return o},i.invertExtent=function(n){return n=r.indexOf(n),0>n?[0/0,0/0]:[n>0?o[n-1]:e[0],n<o.length?o[n]:e[e.length-1]]},i.copy=function(){return Wi(e,r)},u()}function Ji(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return Ji(n,t,e)},u()}function Gi(n,t){function e(e){return e>=e?t[Zo.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return Gi(n,t)},e}function Ki(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Oi(n,t)},t.tickFormat=function(t,e){return Yi(n,t,e)},t.copy=function(){return Ki(n)},t}function Qi(n){return n.innerRadius}function no(n){return n.outerRadius}function to(n){return n.startAngle}function eo(n){return n.endAngle}function ro(n){function t(t){function o(){s.push("M",i(n(l),a))}for(var c,s=[],l=[],f=-1,h=t.length,g=bt(e),p=bt(r);++f<h;)u.call(this,c=t[f],f)?l.push([+g.call(this,c,f),+p.call(this,c,f)]):l.length&&(o(),l=[]);return l.length&&o(),s.length?s.join(""):null}var e=wr,r=Sr,u=we,i=uo,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=xs.get(n)||uo).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function uo(n){return n.join("L")}function io(n){return uo(n)+"Z"}function oo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function ao(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function co(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function so(n,t){return n.length<4?uo(n):n[1]+ho(n.slice(1,n.length-1),go(n,t))}function lo(n,t){return n.length<3?uo(n):n[0]+ho((n.push(n[0]),n),go([n[n.length-2]].concat(n,[n[1]]),t))}function fo(n,t){return n.length<3?uo(n):n[0]+ho(n,go(n,t))}function ho(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return uo(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var s=2;s<t.length;s++,c++)i=n[c],a=t[s],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var l=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+l[0]+","+l[1]}return r}function go(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function po(n){if(n.length<3)return uo(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",xo(bs,o),",",xo(bs,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Mo(c,o,a);return n.pop(),c.push("L",r),c.join("")}function vo(n){if(n.length<4)return uo(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(xo(bs,i)+","+xo(bs,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Mo(e,i,o);return e.join("")}function mo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[xo(bs,o),",",xo(bs,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Mo(t,o,a);return t.join("")}function yo(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,s=-1;++s<=e;)r=n[s],u=s/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return po(n)}function xo(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Mo(n,t,e){n.push("C",xo(Ms,t),",",xo(Ms,e),",",xo(_s,t),",",xo(_s,e),",",xo(bs,t),",",xo(bs,e))}function _o(n,t){return(t[1]-n[1])/(t[0]-n[0])}function bo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=_o(u,i);++t<e;)r[t]=(o+(o=_o(u=i,i=n[t+1])))/2;return r[t]=o,r}function wo(n){for(var t,e,r,u,i=[],o=bo(n),a=-1,c=n.length-1;++a<c;)t=_o(n[a],n[a+1]),ua(t)<ka?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function So(n){return n.length<3?uo(n):n[0]+ho(n,wo(n))}function ko(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]+ms,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Eo(n){function t(t){function c(){v.push("M",a(n(m),f),l,s(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,x=t.length,M=bt(e),_=bt(u),b=e===r?function(){return g}:bt(r),w=u===i?function(){return p}:bt(i);++y<x;)o.call(this,h=t[y],y)?(d.push([g=+M.call(this,h,y),p=+_.call(this,h,y)]),m.push([+b.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=wr,r=wr,u=0,i=Sr,o=we,a=uo,c=a.key,s=a,l="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=xs.get(n)||uo).key,s=a.reverse||a,l=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Ao(n){return n.radius}function Co(n){return[n.x,n.y]}function No(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]+ms;return[e*Math.cos(r),e*Math.sin(r)]}}function zo(){return 64}function Lo(){return"circle"}function To(n){var t=Math.sqrt(n/ba);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function qo(n,t){return sa(n,Cs),n.id=t,n}function Ro(n,t,e,r){var u=n.id;return P(n,"function"==typeof e?function(n,i,o){n.__transition__[u].tween.set(t,r(e.call(n,n.__data__,i,o)))}:(e=r(e),function(n){n.__transition__[u].tween.set(t,e)}))}function Do(n){return null==n&&(n=""),function(){this.textContent=n}}function Po(n,t,e,r){var u=n.__transition__||(n.__transition__={active:0,count:0}),i=u[e];if(!i){var a=r.time;i=u[e]={tween:new o,time:a,ease:r.ease,delay:r.delay,duration:r.duration},++u.count,Zo.timer(function(r){function o(r){return u.active>e?s():(u.active=e,i.event&&i.event.start.call(n,l,t),i.tween.forEach(function(e,r){(r=r.call(n,l,t))&&v.push(r)}),Zo.timer(function(){return p.c=c(r||1)?we:c,1},0,a),void 0)}function c(r){if(u.active!==e)return s();for(var o=r/g,a=f(o),c=v.length;c>0;)v[--c].call(n,a); - return o>=1?(i.event&&i.event.end.call(n,l,t),s()):void 0}function s(){return--u.count?delete u[e]:delete n.__transition__,1}var l=n.__data__,f=i.ease,h=i.delay,g=i.duration,p=Ba,v=[];return p.t=h+a,r>=h?o(r-h):(p.c=o,void 0)},0,a)}}function Uo(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}function jo(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function Ho(n){return n.toISOString()}function Fo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=Zo.bisect(Us,u);return i==Us.length?[t.year,Fi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Us[i-1]<Us[i]/u?i-1:i]:[Fs,Fi(n,e)[2]]}return r.invert=function(t){return Oo(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Oo)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Oo(+e+1),t).length}var i=r.domain(),o=Li(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Ri(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Oo(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Oo(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Li(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Oo(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Fo(n.copy(),t,e)},ji(r,n)}function Oo(n){return new Date(n)}function Yo(n){return JSON.parse(n.responseText)}function Io(n){var t=$o.createRange();return t.selectNode($o.body),t.createContextualFragment(n.responseText)}var Zo={version:"3.4.11"};Date.now||(Date.now=function(){return+new Date});var Vo=[].slice,Xo=function(n){return Vo.call(n)},$o=document,Bo=$o.documentElement,Wo=window;try{Xo(Bo.childNodes)[0].nodeType}catch(Jo){Xo=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}try{$o.createElement("div").style.setProperty("opacity",0,"")}catch(Go){var Ko=Wo.Element.prototype,Qo=Ko.setAttribute,na=Ko.setAttributeNS,ta=Wo.CSSStyleDeclaration.prototype,ea=ta.setProperty;Ko.setAttribute=function(n,t){Qo.call(this,n,t+"")},Ko.setAttributeNS=function(n,t,e){na.call(this,n,t,e+"")},ta.setProperty=function(n,t,e){ea.call(this,n,t+"",e)}}Zo.ascending=n,Zo.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},Zo.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},Zo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},Zo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o&&!(null!=(e=u=n[i])&&e>=e);)e=u=void 0;for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o&&!(null!=(e=u=t.call(n,n[i],i))&&e>=e);)e=void 0;for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},Zo.sum=function(n,t){var e,r=0,u=n.length,i=-1;if(1===arguments.length)for(;++i<u;)isNaN(e=+n[i])||(r+=e);else for(;++i<u;)isNaN(e=+t.call(n,n[i],i))||(r+=e);return r},Zo.mean=function(n,e){var r,u=0,i=n.length,o=-1,a=i;if(1===arguments.length)for(;++o<i;)t(r=n[o])?u+=r:--a;else for(;++o<i;)t(r=e.call(n,n[o],o))?u+=r:--a;return a?u/a:void 0},Zo.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},Zo.median=function(e,r){return arguments.length>1&&(e=e.map(r)),e=e.filter(t),e.length?Zo.quantile(e.sort(n),.5):void 0};var ra=e(n);Zo.bisectLeft=ra.left,Zo.bisect=Zo.bisectRight=ra.right,Zo.bisector=function(t){return e(1===t.length?function(e,r){return n(t(e),r)}:t)},Zo.shuffle=function(n){for(var t,e,r=n.length;r;)e=0|Math.random()*r--,t=n[r],n[r]=n[e],n[e]=t;return n},Zo.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},Zo.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},Zo.zip=function(){if(!(u=arguments.length))return[];for(var n=-1,t=Zo.min(arguments,r),e=new Array(t);++n<t;)for(var u,i=-1,o=e[n]=new Array(u);++i<u;)o[i]=arguments[i][n];return e},Zo.transpose=function(n){return Zo.zip.apply(Zo,n)},Zo.keys=function(n){var t=[];for(var e in n)t.push(e);return t},Zo.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},Zo.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},Zo.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ua=Math.abs;Zo.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/e)throw new Error("infinite range");var r,i=[],o=u(ua(e)),a=-1;if(n*=o,t*=o,e*=o,0>e)for(;(r=n+e*++a)>t;)i.push(r/o);else for(;(r=n+e*++a)<t;)i.push(r/o);return i},Zo.map=function(n){var t=new o;if(n instanceof o)n.forEach(function(n,e){t.set(n,e)});else for(var e in n)t.set(e,n[e]);return t},i(o,{has:a,get:function(n){return this[ia+n]},set:function(n,t){return this[ia+n]=t},remove:c,keys:s,values:function(){var n=[];return this.forEach(function(t,e){n.push(e)}),n},entries:function(){var n=[];return this.forEach(function(t,e){n.push({key:t,value:e})}),n},size:l,empty:f,forEach:function(n){for(var t in this)t.charCodeAt(0)===oa&&n.call(this,t.substring(1),this[t])}});var ia="\x00",oa=ia.charCodeAt(0);Zo.nest=function(){function n(t,a,c){if(c>=i.length)return r?r.call(u,a):e?a.sort(e):a;for(var s,l,f,h,g=-1,p=a.length,v=i[c++],d=new o;++g<p;)(h=d.get(s=v(l=a[g])))?h.push(l):d.set(s,[l]);return t?(l=t(),f=function(e,r){l.set(e,n(t,r,c))}):(l={},f=function(e,r){l[e]=n(t,r,c)}),d.forEach(f),l}function t(n,e){if(e>=i.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],a=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(Zo.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return a[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},Zo.set=function(n){var t=new h;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},i(h,{has:a,add:function(n){return this[ia+n]=!0,n},remove:function(n){return n=ia+n,n in this&&delete this[n]},values:s,size:l,empty:f,forEach:function(n){for(var t in this)t.charCodeAt(0)===oa&&n.call(this,t.substring(1))}}),Zo.behavior={},Zo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=g(n,t,t[e]);return n};var aa=["webkit","ms","moz","Moz","o","O"];Zo.dispatch=function(){for(var n=new d,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=m(n);return n},d.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},Zo.event=null,Zo.requote=function(n){return n.replace(ca,"\\$&")};var ca=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,sa={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},la=function(n,t){return t.querySelector(n)},fa=function(n,t){return t.querySelectorAll(n)},ha=Bo.matches||Bo[p(Bo,"matchesSelector")],ga=function(n,t){return ha.call(n,t)};"function"==typeof Sizzle&&(la=function(n,t){return Sizzle(n,t)[0]||null},fa=Sizzle,ga=Sizzle.matchesSelector),Zo.selection=function(){return ma};var pa=Zo.selection.prototype=[];pa.select=function(n){var t,e,r,u,i=[];n=b(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,s=r.length;++c<s;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return _(i)},pa.selectAll=function(n){var t,e,r=[];n=w(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=Xo(n.call(e,e.__data__,a,u))),t.parentNode=e);return _(r)};var va={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};Zo.ns={prefix:va,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.substring(0,t),n=n.substring(t+1)),va.hasOwnProperty(e)?{space:va[e],local:n}:n}},pa.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=Zo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(S(t,n[t]));return this}return this.each(S(n,t))},pa.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=A(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!E(n[u]).test(t))return!1;return!0}for(t in n)this.each(C(t,n[t]));return this}return this.each(C(n,t))},pa.style=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t="");for(e in n)this.each(z(e,n[e],t));return this}if(2>r)return Wo.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return this.each(z(n,t,e))},pa.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(L(t,n[t]));return this}return this.each(L(n,t))},pa.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},pa.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},pa.append=function(n){return n=T(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},pa.insert=function(n,t){return n=T(n),t=b(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},pa.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},pa.data=function(n,t){function e(n,e){var r,u,i,a=n.length,f=e.length,h=Math.min(a,f),g=new Array(f),p=new Array(f),v=new Array(a);if(t){var d,m=new o,y=new o,x=[];for(r=-1;++r<a;)d=t.call(u=n[r],u.__data__,r),m.has(d)?v[r]=u:m.set(d,u),x.push(d);for(r=-1;++r<f;)d=t.call(e,i=e[r],r),(u=m.get(d))?(g[r]=u,u.__data__=i):y.has(d)||(p[r]=q(i)),y.set(d,i),m.remove(d);for(r=-1;++r<a;)m.has(x[r])&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=q(i);for(;f>r;++r)p[r]=q(e[r]);for(;a>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,c.push(p),s.push(g),l.push(v)}var r,u,i=-1,a=this.length;if(!arguments.length){for(n=new Array(a=(r=this[0]).length);++i<a;)(u=r[i])&&(n[i]=u.__data__);return n}var c=U([]),s=_([]),l=_([]);if("function"==typeof n)for(;++i<a;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<a;)e(r=this[i],n);return s.enter=function(){return c},s.exit=function(){return l},s},pa.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},pa.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=R(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return _(u)},pa.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},pa.sort=function(n){n=D.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},pa.each=function(n){return P(this,function(t,e,r){n.call(t,t.__data__,e,r)})},pa.call=function(n){var t=Xo(arguments);return n.apply(t[0]=this,t),this},pa.empty=function(){return!this.node()},pa.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},pa.size=function(){var n=0;return this.each(function(){++n}),n};var da=[];Zo.selection.enter=U,Zo.selection.enter.prototype=da,da.append=pa.append,da.empty=pa.empty,da.node=pa.node,da.call=pa.call,da.size=pa.size,da.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var s=-1,l=u.length;++s<l;)(i=u[s])?(t.push(r[s]=e=n.call(u.parentNode,i.__data__,s,a)),e.__data__=i.__data__):t.push(null)}return _(o)},da.insert=function(n,t){return arguments.length<2&&(t=j(this)),pa.insert.call(this,n,t)},pa.transition=function(){for(var n,t,e=Ss||++Ns,r=[],u=ks||{time:Date.now(),ease:xu,delay:0,duration:250},i=-1,o=this.length;++i<o;){r.push(n=[]);for(var a=this[i],c=-1,s=a.length;++c<s;)(t=a[c])&&Po(t,c,e,u),n.push(t)}return qo(r,e)},pa.interrupt=function(){return this.each(H)},Zo.select=function(n){var t=["string"==typeof n?la(n,$o):n];return t.parentNode=Bo,_([t])},Zo.selectAll=function(n){var t=Xo("string"==typeof n?fa(n,$o):n);return t.parentNode=Bo,_([t])};var ma=Zo.select(Bo);pa.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(F(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(F(n,t,e))};var ya=Zo.map({mouseenter:"mouseover",mouseleave:"mouseout"});ya.forEach(function(n){"on"+n in $o&&ya.remove(n)});var xa="onselectstart"in $o?null:p(Bo.style,"userSelect"),Ma=0;Zo.mouse=function(n){return Z(n,x())};var _a=/WebKit/.test(Wo.navigator.userAgent)?-1:0;Zo.touches=function(n,t){return arguments.length<2&&(t=x().touches),t?Xo(t).map(function(t){var e=Z(n,t);return e.identifier=t.identifier,e}):[]},Zo.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",i)}function t(n,t,u,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-x[0],e=r[1]-x[1],p|=n|e,x=r,g({type:"drag",x:r[0]+s[0],y:r[1]+s[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&Zo.event.target===f),g({type:"dragend"}))}var s,l=this,f=Zo.event.target,h=l.parentNode,g=e.of(l,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=Zo.select(u()).on(i+d,a).on(o+d,c),y=I(),x=t(h,v);r?(s=r.apply(l,arguments),s=[s.x-x[0],s.y-x[1]]):s=[0,0],g({type:"dragstart"})}}var e=M(n,"drag","dragstart","dragend"),r=null,u=t(v,Zo.mouse,$,"mousemove","mouseup"),i=t(V,Zo.touch,X,"touchmove","touchend");return n.origin=function(t){return arguments.length?(r=t,n):r},Zo.rebind(n,e,"on")};var ba=Math.PI,wa=2*ba,Sa=ba/2,ka=1e-6,Ea=ka*ka,Aa=ba/180,Ca=180/ba,Na=Math.SQRT2,za=2,La=4;Zo.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=Q(v),o=i/(za*h)*(e*nt(Na*t+v)-K(v));return[r+o*s,u+o*l,i*e/Q(Na*t+v)]}return[r+n*s,u+n*l,i*Math.exp(Na*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],s=o-r,l=a-u,f=s*s+l*l,h=Math.sqrt(f),g=(c*c-i*i+La*f)/(2*i*za*h),p=(c*c-i*i-La*f)/(2*c*za*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Na;return e.duration=1e3*y,e},Zo.behavior.zoom=function(){function n(n){n.on(A,s).on(Ra+".zoom",f).on("dblclick.zoom",h).on(z,l)}function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}function r(n){S.k=Math.max(E[0],Math.min(E[1],n))}function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}function i(){_&&_.domain(x.range().map(function(n){return(n-S.x)/S.k}).map(x.invert)),w&&w.domain(b.range().map(function(n){return(n-S.y)/S.k}).map(b.invert))}function o(n){n({type:"zoomstart"})}function a(n){i(),n({type:"zoom",scale:S.k,translate:[S.x,S.y]})}function c(n){n({type:"zoomend"})}function s(){function n(){l=1,u(Zo.mouse(r),h),a(s)}function e(){f.on(C,null).on(N,null),g(l&&Zo.event.target===i),c(s)}var r=this,i=Zo.event.target,s=L.of(r,arguments),l=0,f=Zo.select(Wo).on(C,n).on(N,e),h=t(Zo.mouse(r)),g=I();H.call(r),o(s)}function l(){function n(){var n=Zo.touches(g);return h=S.k,n.forEach(function(n){n.identifier in v&&(v[n.identifier]=t(n))}),n}function e(){var t=Zo.event.target;Zo.select(t).on(M,i).on(_,f),b.push(t);for(var e=Zo.event.changedTouches,o=0,c=e.length;c>o;++o)v[e[o].identifier]=null;var s=n(),l=Date.now();if(1===s.length){if(500>l-m){var h=s[0],g=v[h.identifier];r(2*S.k),u(h,g),y(),a(p)}m=l}else if(s.length>1){var h=s[0],x=s[1],w=h[0]-x[0],k=h[1]-x[1];d=w*w+k*k}}function i(){for(var n,t,e,i,o=Zo.touches(g),c=0,s=o.length;s>c;++c,i=null)if(e=o[c],i=v[e.identifier]){if(t)break;n=e,t=i}if(i){var l=(l=e[0]-n[0])*l+(l=e[1]-n[1])*l,f=d&&Math.sqrt(l/d);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*h)}m=null,u(n,t),a(p)}function f(){if(Zo.event.touches.length){for(var t=Zo.event.changedTouches,e=0,r=t.length;r>e;++e)delete v[t[e].identifier];for(var u in v)return void n()}Zo.selectAll(b).on(x,null),w.on(A,s).on(z,l),k(),c(p)}var h,g=this,p=L.of(g,arguments),v={},d=0,x=".zoom-"+Zo.event.changedTouches[0].identifier,M="touchmove"+x,_="touchend"+x,b=[],w=Zo.select(g).on(A,null).on(z,e),k=I();H.call(g),e(),o(p)}function f(){var n=L.of(this,arguments);d?clearTimeout(d):(g=t(p=v||Zo.mouse(this)),H.call(this),o(n)),d=setTimeout(function(){d=null,c(n)},50),y(),r(Math.pow(2,.002*Ta())*S.k),u(p,g),a(n)}function h(){var n=L.of(this,arguments),e=Zo.mouse(this),i=t(e),s=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,Zo.event.shiftKey?Math.ceil(s)-1:Math.floor(s)+1)),u(e,i),a(n),c(n)}var g,p,v,d,m,x,_,b,w,S={x:0,y:0,k:1},k=[960,500],E=qa,A="mousedown.zoom",C="mousemove.zoom",N="mouseup.zoom",z="touchstart.zoom",L=M(n,"zoomstart","zoom","zoomend");return n.event=function(n){n.each(function(){var n=L.of(this,arguments),t=S;Ss?Zo.select(this).transition().each("start.zoom",function(){S=this.__chart__||{x:0,y:0,k:1},o(n)}).tween("zoom:zoom",function(){var e=k[0],r=k[1],u=e/2,i=r/2,o=Zo.interpolateZoom([(u-S.x)/S.k,(i-S.y)/S.k,e/S.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),c=e/r[2];this.__chart__=S={x:u-r[0]*c,y:i-r[1]*c,k:c},a(n)}}).each("end.zoom",function(){c(n)}):(this.__chart__=S,o(n),a(n),c(n))})},n.translate=function(t){return arguments.length?(S={x:+t[0],y:+t[1],k:S.k},i(),n):[S.x,S.y]},n.scale=function(t){return arguments.length?(S={x:S.x,y:S.y,k:+t},i(),n):S.k},n.scaleExtent=function(t){return arguments.length?(E=null==t?qa:[+t[0],+t[1]],n):E},n.center=function(t){return arguments.length?(v=t&&[+t[0],+t[1]],n):v},n.size=function(t){return arguments.length?(k=t&&[+t[0],+t[1]],n):k},n.x=function(t){return arguments.length?(_=t,x=t.copy(),S={x:0,y:0,k:1},n):_},n.y=function(t){return arguments.length?(w=t,b=t.copy(),S={x:0,y:0,k:1},n):w},Zo.rebind(n,L,"on")};var Ta,qa=[0,1/0],Ra="onwheel"in $o?(Ta=function(){return-Zo.event.deltaY*(Zo.event.deltaMode?120:1)},"wheel"):"onmousewheel"in $o?(Ta=function(){return Zo.event.wheelDelta},"mousewheel"):(Ta=function(){return-Zo.event.detail},"MozMousePixelScroll");Zo.color=et,et.prototype.toString=function(){return this.rgb()+""},Zo.hsl=rt;var Da=rt.prototype=new et;Da.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new rt(this.h,this.s,this.l/n)},Da.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new rt(this.h,this.s,n*this.l)},Da.rgb=function(){return ut(this.h,this.s,this.l)},Zo.hcl=it;var Pa=it.prototype=new et;Pa.brighter=function(n){return new it(this.h,this.c,Math.min(100,this.l+Ua*(arguments.length?n:1)))},Pa.darker=function(n){return new it(this.h,this.c,Math.max(0,this.l-Ua*(arguments.length?n:1)))},Pa.rgb=function(){return ot(this.h,this.c,this.l).rgb()},Zo.lab=at;var Ua=18,ja=.95047,Ha=1,Fa=1.08883,Oa=at.prototype=new et;Oa.brighter=function(n){return new at(Math.min(100,this.l+Ua*(arguments.length?n:1)),this.a,this.b)},Oa.darker=function(n){return new at(Math.max(0,this.l-Ua*(arguments.length?n:1)),this.a,this.b)},Oa.rgb=function(){return ct(this.l,this.a,this.b)},Zo.rgb=gt;var Ya=gt.prototype=new et;Ya.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new gt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new gt(u,u,u)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new gt(n*this.r,n*this.g,n*this.b)},Ya.hsl=function(){return yt(this.r,this.g,this.b)},Ya.toString=function(){return"#"+dt(this.r)+dt(this.g)+dt(this.b)};var Ia=Zo.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ia.forEach(function(n,t){Ia.set(n,pt(t))}),Zo.functor=bt,Zo.xhr=St(wt),Zo.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=kt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(l>=s)return o;if(u)return u=!1,i;var t=l;if(34===n.charCodeAt(t)){for(var e=t;e++<s;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}l=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++l):10===r&&(u=!0),n.substring(t+1,e).replace(/""/g,'"')}for(;s>l;){var r=n.charCodeAt(l++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(l)&&(++l,++a);else if(r!==c)continue;return n.substring(t,l-a)}return n.substring(t)}for(var r,u,i={},o={},a=[],s=n.length,l=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();(!t||(h=t(h,f++)))&&a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new h,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},Zo.csv=Zo.dsv(",","text/csv"),Zo.tsv=Zo.dsv(" ","text/tab-separated-values"),Zo.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=x().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return Z(n,r)};var Za,Va,Xa,$a,Ba,Wa=Wo[p(Wo,"requestAnimationFrame")]||function(n){setTimeout(n,17)};Zo.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Va?Va.n=i:Za=i,Va=i,Xa||($a=clearTimeout($a),Xa=1,Wa(At))},Zo.timer.flush=function(){Ct(),Nt()},Zo.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var Ja=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Lt);Zo.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=Zo.round(n,zt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),Ja[8+e/3]};var Ga=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,Ka=Zo.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=Zo.round(n,zt(n,t))).toFixed(Math.max(0,Math.min(20,zt(n*(1+1e-15),t))))}}),Qa=Zo.time={},nc=Date;Rt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){tc.setUTCDate.apply(this._,arguments)},setDay:function(){tc.setUTCDay.apply(this._,arguments)},setFullYear:function(){tc.setUTCFullYear.apply(this._,arguments)},setHours:function(){tc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){tc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){tc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){tc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){tc.setUTCSeconds.apply(this._,arguments)},setTime:function(){tc.setTime.apply(this._,arguments)}};var tc=Date.prototype;Qa.year=Dt(function(n){return n=Qa.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),Qa.years=Qa.year.range,Qa.years.utc=Qa.year.utc.range,Qa.day=Dt(function(n){var t=new nc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),Qa.days=Qa.day.range,Qa.days.utc=Qa.day.utc.range,Qa.dayOfYear=function(n){var t=Qa.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=Qa[n]=Dt(function(n){return(n=Qa.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=Qa.year(n).getDay();return Math.floor((Qa.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});Qa[n+"s"]=e.range,Qa[n+"s"].utc=e.utc.range,Qa[n+"OfYear"]=function(n){var e=Qa.year(n).getDay();return Math.floor((Qa.dayOfYear(n)+(e+t)%7)/7)}}),Qa.week=Qa.sunday,Qa.weeks=Qa.sunday.range,Qa.weeks.utc=Qa.sunday.utc.range,Qa.weekOfYear=Qa.sundayOfYear;var ec={"-":"",_:" ",0:"0"},rc=/^\s*\d+/,uc=/^%/;Zo.locale=function(n){return{numberFormat:Tt(n),timeFormat:Ut(n)}};var ic=Zo.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});Zo.format=ic.numberFormat,Zo.geo={},ue.prototype={s:0,t:0,add:function(n){ie(n,this.t,oc),ie(oc.s,this.s,this),this.s?this.t+=oc.t:this.s=oc.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var oc=new ue;Zo.geo.stream=function(n,t){n&&ac.hasOwnProperty(n.type)?ac[n.type](n,t):oe(n,t)};var ac={Feature:function(n,t){oe(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)oe(e[r].geometry,t)}},cc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){ae(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)ae(e[r],t,0)},Polygon:function(n,t){ce(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)ce(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)oe(e[r],t)}};Zo.geo.area=function(n){return sc=0,Zo.geo.stream(n,fc),sc};var sc,lc=new ue,fc={sphere:function(){sc+=4*ba},point:v,lineStart:v,lineEnd:v,polygonStart:function(){lc.reset(),fc.lineStart=se},polygonEnd:function(){var n=2*lc;sc+=0>n?4*ba+n:n,fc.lineStart=fc.lineEnd=fc.point=v}};Zo.geo.bounds=function(){function n(n,t){x.push(M=[l=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=le([t*Aa,e*Aa]);if(m){var u=he(m,r),i=[u[1],-u[0],0],o=he(i,u);ve(o),o=de(o);var c=t-p,s=c>0?1:-1,v=o[0]*Ca*s,d=ua(c)>180;if(d^(v>s*p&&s*t>v)){var y=o[1]*Ca;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>s*p&&s*t>v)){var y=-o[1]*Ca;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t):h>=l?(l>t&&(l=t),t>h&&(h=t)):t>p?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t)}else n(t,e);m=r,p=t}function e(){_.point=t}function r(){M[0]=l,M[1]=h,_.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ua(r)>180?r+(r>0?360:-360):r}else v=n,d=e;fc.point(n,e),t(n,e)}function i(){fc.lineStart()}function o(){u(v,d),fc.lineEnd(),ua(y)>ka&&(l=-(h=180)),M[0]=l,M[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function s(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var l,f,h,g,p,v,d,m,y,x,M,_={point:n,lineStart:e,lineEnd:r,polygonStart:function(){_.point=u,_.lineStart=i,_.lineEnd=o,y=0,fc.polygonStart()},polygonEnd:function(){fc.polygonEnd(),_.point=n,_.lineStart=e,_.lineEnd=r,0>lc?(l=-(h=180),f=-(g=90)):y>ka?g=90:-ka>y&&(f=-90),M[0]=l,M[1]=h}};return function(n){g=h=-(l=f=1/0),x=[],Zo.geo.stream(n,_);var t=x.length;if(t){x.sort(c);for(var e,r=1,u=x[0],i=[u];t>r;++r)e=x[r],s(e[0],u)||s(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e); - for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,l=e[0],h=u[1])}return x=M=null,1/0===l||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[l,f],[h,g]]}}(),Zo.geo.centroid=function(n){hc=gc=pc=vc=dc=mc=yc=xc=Mc=_c=bc=0,Zo.geo.stream(n,wc);var t=Mc,e=_c,r=bc,u=t*t+e*e+r*r;return Ea>u&&(t=mc,e=yc,r=xc,ka>gc&&(t=pc,e=vc,r=dc),u=t*t+e*e+r*r,Ea>u)?[0/0,0/0]:[Math.atan2(e,t)*Ca,G(r/Math.sqrt(u))*Ca]};var hc,gc,pc,vc,dc,mc,yc,xc,Mc,_c,bc,wc={sphere:v,point:ye,lineStart:Me,lineEnd:_e,polygonStart:function(){wc.lineStart=be},polygonEnd:function(){wc.lineStart=Me}},Sc=Ae(we,Te,Re,[-ba,-ba/2]),kc=1e9;Zo.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ue(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(Zo.geo.conicEqualArea=function(){return He(Fe)}).raw=Fe,Zo.geo.albers=function(){return Zo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},Zo.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=Zo.geo.albers(),o=Zo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=Zo.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var s=i.scale(),l=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[l-.455*s,f-.238*s],[l+.455*s,f+.238*s]]).stream(c).point,r=o.translate([l-.307*s,f+.201*s]).clipExtent([[l-.425*s+ka,f+.12*s+ka],[l-.214*s-ka,f+.234*s-ka]]).stream(c).point,u=a.translate([l-.205*s,f+.212*s]).clipExtent([[l-.214*s+ka,f+.166*s+ka],[l-.115*s-ka,f+.234*s-ka]]).stream(c).point,n},n.scale(1070)};var Ec,Ac,Cc,Nc,zc,Lc,Tc={point:v,lineStart:v,lineEnd:v,polygonStart:function(){Ac=0,Tc.lineStart=Oe},polygonEnd:function(){Tc.lineStart=Tc.lineEnd=Tc.point=v,Ec+=ua(Ac/2)}},qc={point:Ye,lineStart:v,lineEnd:v,polygonStart:v,polygonEnd:v},Rc={point:Ve,lineStart:Xe,lineEnd:$e,polygonStart:function(){Rc.lineStart=Be},polygonEnd:function(){Rc.point=Ve,Rc.lineStart=Xe,Rc.lineEnd=$e}};Zo.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),Zo.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Ec=0,Zo.geo.stream(n,u(Tc)),Ec},n.centroid=function(n){return pc=vc=dc=mc=yc=xc=Mc=_c=bc=0,Zo.geo.stream(n,u(Rc)),bc?[Mc/bc,_c/bc]:xc?[mc/xc,yc/xc]:dc?[pc/dc,vc/dc]:[0/0,0/0]},n.bounds=function(n){return zc=Lc=-(Cc=Nc=1/0),Zo.geo.stream(n,u(qc)),[[Cc,Nc],[zc,Lc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||Ge(n):wt,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new Ie:new We(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(Zo.geo.albersUsa()).context(null)},Zo.geo.transform=function(n){return{stream:function(t){var e=new Ke(t);for(var r in n)e[r]=n[r];return e}}},Ke.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},Zo.geo.projection=nr,Zo.geo.projectionMutator=tr,(Zo.geo.equirectangular=function(){return nr(rr)}).raw=rr.invert=rr,Zo.geo.rotation=function(n){function t(t){return t=n(t[0]*Aa,t[1]*Aa),t[0]*=Ca,t[1]*=Ca,t}return n=ir(n[0]%360*Aa,n[1]*Aa,n.length>2?n[2]*Aa:0),t.invert=function(t){return t=n.invert(t[0]*Aa,t[1]*Aa),t[0]*=Ca,t[1]*=Ca,t},t},ur.invert=rr,Zo.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=ir(-n[0]*Aa,-n[1]*Aa,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Ca,n[1]*=Ca}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=sr((t=+r)*Aa,u*Aa),n):t},n.precision=function(r){return arguments.length?(e=sr(t*Aa,(u=+r)*Aa),n):u},n.angle(90)},Zo.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Aa,u=n[1]*Aa,i=t[1]*Aa,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),s=Math.cos(u),l=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=s*l-c*f*a)*e),c*l+s*f*a)},Zo.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return Zo.range(Math.ceil(i/d)*d,u,d).map(h).concat(Zo.range(Math.ceil(s/m)*m,c,m).map(g)).concat(Zo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ua(n%d)>ka}).map(l)).concat(Zo.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ua(n%m)>ka}).map(f))}var e,r,u,i,o,a,c,s,l,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(s).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],s=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),s>c&&(t=s,s=c,c=t),n.precision(y)):[[i,s],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,l=fr(a,o,90),f=hr(r,e,y),h=fr(s,c,90),g=hr(i,u,y),n):y},n.majorExtent([[-180,-90+ka],[180,90-ka]]).minorExtent([[-180,-80-ka],[180,80+ka]])},Zo.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=gr,u=pr;return n.distance=function(){return Zo.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},Zo.geo.interpolate=function(n,t){return vr(n[0]*Aa,n[1]*Aa,t[0]*Aa,t[1]*Aa)},Zo.geo.length=function(n){return Dc=0,Zo.geo.stream(n,Pc),Dc};var Dc,Pc={sphere:v,point:v,lineStart:dr,lineEnd:v,polygonStart:v,polygonEnd:v},Uc=mr(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(Zo.geo.azimuthalEqualArea=function(){return nr(Uc)}).raw=Uc;var jc=mr(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},wt);(Zo.geo.azimuthalEquidistant=function(){return nr(jc)}).raw=jc,(Zo.geo.conicConformal=function(){return He(yr)}).raw=yr,(Zo.geo.conicEquidistant=function(){return He(xr)}).raw=xr;var Hc=mr(function(n){return 1/n},Math.atan);(Zo.geo.gnomonic=function(){return nr(Hc)}).raw=Hc,Mr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Sa]},(Zo.geo.mercator=function(){return _r(Mr)}).raw=Mr;var Fc=mr(function(){return 1},Math.asin);(Zo.geo.orthographic=function(){return nr(Fc)}).raw=Fc;var Oc=mr(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(Zo.geo.stereographic=function(){return nr(Oc)}).raw=Oc,br.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Sa]},(Zo.geo.transverseMercator=function(){var n=_r(br),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=br,Zo.geom={},Zo.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=bt(e),i=bt(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(Er),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var s=kr(a),l=kr(c),f=l[0]===s[0],h=l[l.length-1]===s[s.length-1],g=[];for(t=s.length-1;t>=0;--t)g.push(n[a[s[t]][2]]);for(t=+f;t<l.length-h;++t)g.push(n[a[l[t]][2]]);return g}var e=wr,r=Sr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},Zo.geom.polygon=function(n){return sa(n,Yc),n};var Yc=Zo.geom.polygon.prototype=[];Yc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Yc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Yc.clip=function(n){for(var t,e,r,u,i,o,a=Nr(n),c=-1,s=this.length-Nr(this),l=this[s-1];++c<s;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Ar(o,l,u)?(Ar(i,l,u)||n.push(Cr(i,o,l,u)),n.push(o)):Ar(i,l,u)&&n.push(Cr(i,o,l,u)),i=o;a&&n.push(n[0]),l=u}return n};var Ic,Zc,Vc,Xc,$c,Bc=[],Wc=[];Ur.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Hr),t.length},Wr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},Jr.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=nu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(Kr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Qr(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(Qr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Kr(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?nu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return n.C=!1,void 0;do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,Kr(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,Qr(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,Kr(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,Qr(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,Kr(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,Qr(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},Zo.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return tu(e(n),a).cells.forEach(function(e,a){var c=e.edges,s=e.site,l=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):s.x>=r&&s.x<=i&&s.y>=u&&s.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];l.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/ka)*ka,y:Math.round(o(n,t)/ka)*ka,i:t}})}var r=wr,u=Sr,i=r,o=u,a=Jc;return n?t(n):(t.links=function(n){return tu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return tu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Hr),c=-1,s=a.length,l=a[s-1].edge,f=l.l===o?l.r:l.l;++c<s;)u=l,i=f,l=a[c].edge,f=l.l===o?l.r:l.l,r<i.i&&r<f.i&&ru(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=bt(r=n),t):r},t.y=function(n){return arguments.length?(o=bt(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?Jc:n,t):a===Jc?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===Jc?null:a&&a[1]},t)};var Jc=[[-1e6,-1e6],[1e6,1e6]];Zo.geom.delaunay=function(n){return Zo.geom.voronoi().triangles(n)},Zo.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,l=n.y;if(null!=c)if(ua(c-e)+ua(l-r)<.01)s(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,s(n,f,c,l,u,i,o,a),s(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else s(n,t,e,r,u,i,o,a)}function s(n,t,e,r,u,o,a,c){var s=.5*(u+a),l=.5*(o+c),f=e>=s,h=r>=l,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=ou()),f?u=s:a=s,h?o=l:c=l,i(n,t,e,r,u,o,a,c)}var l,f,h,g,p,v,d,m,y,x=bt(a),M=bt(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)l=n[g],l.x<v&&(v=l.x),l.y<d&&(d=l.y),l.x>m&&(m=l.x),l.y>y&&(y=l.y),f.push(l.x),h.push(l.y);else for(g=0;p>g;++g){var _=+x(l=n[g],g),b=+M(l,g);v>_&&(v=_),d>b&&(d=b),_>m&&(m=_),b>y&&(y=b),f.push(_),h.push(b)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=ou();if(k.add=function(n){i(k,n,+x(n,++g),+M(n,g),v,d,m,y)},k.visit=function(n){au(n,k,v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=l=null,k}var o,a=wr,c=Sr;return(o=arguments.length)?(a=uu,c=iu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},Zo.interpolateRgb=cu,Zo.interpolateObject=su,Zo.interpolateNumber=lu,Zo.interpolateString=fu;var Gc=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Kc=new RegExp(Gc.source,"g");Zo.interpolate=hu,Zo.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ia.has(t)||/^(#|rgb\(|hsl\()/.test(t)?cu:fu:t instanceof et?cu:Array.isArray(t)?gu:"object"===e&&isNaN(t)?su:lu)(n,t)}],Zo.interpolateArray=gu;var Qc=function(){return wt},ns=Zo.map({linear:Qc,poly:Mu,quad:function(){return mu},cubic:function(){return yu},sin:function(){return _u},exp:function(){return bu},circle:function(){return wu},elastic:Su,back:ku,bounce:function(){return Eu}}),ts=Zo.map({"in":wt,out:vu,"in-out":du,"out-in":function(n){return du(vu(n))}});Zo.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.substring(0,t):n,r=t>=0?n.substring(t+1):"in";return e=ns.get(e)||Qc,r=ts.get(r)||wt,pu(r(e.apply(null,Vo.call(arguments,1))))},Zo.interpolateHcl=Au,Zo.interpolateHsl=Cu,Zo.interpolateLab=Nu,Zo.interpolateRound=zu,Zo.transform=function(n){var t=$o.createElementNS(Zo.ns.prefix.svg,"g");return(Zo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Lu(e?e.matrix:es)})(n)},Lu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var es={a:1,b:0,c:0,d:1,e:0,f:0};Zo.interpolateTransform=Du,Zo.layout={},Zo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(ju(n[e]));return t}},Zo.layout.chord=function(){function n(){var n,s,f,h,g,p={},v=[],d=Zo.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(s=0,g=-1;++g<i;)s+=u[h][g];v.push(s),m.push(Zo.range(i)),n+=s}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(wa-l*i)/n,s=0,h=-1;++h<i;){for(f=s,g=-1;++g<i;){var y=d[h],x=m[y][g],M=u[y][x],_=s,b=s+=M*n;p[y+"-"+x]={index:y,subindex:x,startAngle:_,endAngle:b,value:M}}r[y]={index:y,startAngle:f,endAngle:s,value:(s-f)/n},s+=l}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,s={},l=0;return s.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,s):u},s.padding=function(n){return arguments.length?(l=n,e=r=null,s):l},s.sortGroups=function(n){return arguments.length?(o=n,e=r=null,s):o},s.sortSubgroups=function(n){return arguments.length?(a=n,e=null,s):a},s.sortChords=function(n){return arguments.length?(c=n,e&&t(),s):c},s.chords=function(){return e||n(),e},s.groups=function(){return r||n(),r},s},Zo.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var s=t.charge/c;n.px-=i*s,n.py-=o*s}return!0}if(t.point&&c&&p>c){var s=t.pointCharge/c;n.px-=i*s,n.py-=o*s}}return!t.charge}}function t(n){n.px=Zo.event.x,n.py=Zo.event.y,a.resume()}var e,r,u,i,o,a={},c=Zo.dispatch("start","tick","end"),s=[1,1],l=.9,f=rs,h=us,g=-30,p=is,v=.1,d=.64,m=[],y=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,x,M,_=m.length,b=y.length;for(e=0;b>e;++e)a=y[e],f=a.source,h=a.target,x=h.x-f.x,M=h.y-f.y,(p=x*x+M*M)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,x*=p,M*=p,h.x-=x*(d=f.weight/(h.weight+f.weight)),h.y-=M*d,f.x+=x*(d=1-d),f.y+=M*d);if((d=r*v)&&(x=s[0]/2,M=s[1]/2,e=-1,d))for(;++e<_;)a=m[e],a.x+=(x-a.x)*d,a.y+=(M-a.y)*d;if(g)for(Vu(t=Zo.geom.quadtree(m),r,o),e=-1;++e<_;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<_;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*l,a.y-=(a.py-(a.py=a.y))*l);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(y=n,a):y},a.size=function(n){return arguments.length?(s=n,a):s},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(l=+n,a):l},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),Zo.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=y[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,s=o.length;++a<s;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,l=y.length,p=s[0],v=s[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;l>t;++t)r=y[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;l>t;++t)u[t]=+f.call(this,y[t],t);else for(t=0;l>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;l>t;++t)i[t]=+h.call(this,y[t],t);else for(t=0;l>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=Zo.behavior.drag().origin(wt).on("dragstart.force",Ou).on("drag.force",t).on("dragend.force",Yu)),arguments.length?(this.on("mouseover.force",Iu).on("mouseout.force",Zu).call(e),void 0):e},Zo.rebind(a,c,"on")};var rs=20,us=1,is=1/0;Zo.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(s=e.call(n,i,i.depth))&&(c=s.length)){for(var c,s,l;--c>=0;)o.push(l=s[c]),l.parent=i,l.depth=i.depth+1;r&&(i.value=0),i.children=s}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Bu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=Gu,e=Wu,r=Ju;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&($u(t,function(n){n.children&&(n.value=0)}),Bu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},Zo.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,s=-1;for(r=t.value?r/t.value:0;++s<o;)n(a=i[s],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=Zo.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Xu(e,r)},Zo.layout.pie=function(){function n(i){var o=i.map(function(e,r){return+t.call(n,e,r)}),a=+("function"==typeof r?r.apply(this,arguments):r),c=(("function"==typeof u?u.apply(this,arguments):u)-a)/Zo.sum(o),s=Zo.range(i.length);null!=e&&s.sort(e===os?function(n,t){return o[t]-o[n]}:function(n,t){return e(i[n],i[t])});var l=[];return s.forEach(function(n){var t;l[n]={data:i[n],value:t=o[n],startAngle:a,endAngle:a+=t*c}}),l}var t=Number,e=os,r=0,u=wa;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n};var os={};Zo.layout.stack=function(){function n(a,c){var s=a.map(function(e,r){return t.call(n,e,r)}),l=s.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,l,c);s=Zo.permute(s,f),l=Zo.permute(l,f);var h,g,p,v=r.call(n,l,c),d=s.length,m=s[0].length;for(g=0;m>g;++g)for(u.call(n,s[0][g],p=v[g],l[0][g][1]),h=1;d>h;++h)u.call(n,s[h][g],p+=l[h-1][g][1],l[h][g][1]);return a}var t=wt,e=ei,r=ri,u=ti,i=Qu,o=ni;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:as.get(t)||ei,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:cs.get(t)||ri,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var as=Zo.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(ui),i=n.map(ii),o=Zo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,s=[],l=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],s.push(e)):(c+=i[e],l.push(e));return l.reverse().concat(s)},reverse:function(n){return Zo.range(n.length).reverse()},"default":ei}),cs=Zo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,s,l=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=s=0,e=1;h>e;++e){for(t=0,u=0;l>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];l>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,s>c&&(s=c)}for(e=0;h>e;++e)g[e]-=s;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ri});Zo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],s=n.map(e,this),l=r.call(this,s,i),f=u.call(this,l,s,i),i=-1,h=s.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=s[i],a>=l[0]&&a<=l[1]&&(o=c[Zo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=si,u=ai;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=bt(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return ci(n,t)}:bt(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},Zo.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],s=u[1],l=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Bu(a,function(n){n.r=+l(n.value)}),Bu(a,pi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/s))/2;Bu(a,function(n){n.r+=f}),Bu(a,pi),Bu(a,function(n){n.r-=f})}return mi(a,c/2,s/2,t?1:1/Math.max(2*a.r/c,2*a.r/s)),o}var t,e=Zo.layout.hierarchy().sort(li),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Xu(n,e)},Zo.layout.tree=function(){function n(n,u){var l=o.call(this,n,u),f=l[0],h=t(f);if(Bu(h,e),h.parent.m=-h.z,$u(h,r),s)$u(f,i);else{var g=f,p=f,v=f;$u(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);$u(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return l}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){wi(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],s=u.m,l=i.m,f=o.m,h=c.m;o=_i(o),u=Mi(u),o&&u;)c=Mi(c),i=_i(i),i.a=n,r=o.z+f-u.z-s+a(o._,u._),r>0&&(bi(Si(o,n,e),n,r),s+=r,l+=r),f+=o.m,s+=u.m,h+=c.m,l+=i.m;o&&!_i(i)&&(i.t=o,i.m+=f-l),u&&!Mi(c)&&(c.t=u,c.m+=s-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=Zo.layout.hierarchy().sort(null).value(null),a=xi,c=[1,1],s=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(s=null==(c=t)?i:null,n):s?null:c},n.nodeSize=function(t){return arguments.length?(s=null==(c=t)?null:i,n):s?c:null},Xu(n,o)},Zo.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],s=0;Bu(c,function(n){var t=n.children;t&&t.length?(n.x=Ei(t),n.y=ki(t)):(n.x=o?s+=e(n,o):0,n.y=0,o=n)});var l=Ai(c),f=Ci(c),h=l.x-e(l,f)/2,g=f.x+e(f,l)/2;return Bu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=Zo.layout.hierarchy().sort(null).value(null),e=xi,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Xu(n,t)},Zo.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,s=f(e),l=[],h=i.slice(),p=1/0,v="slice"===g?s.dx:"dice"===g?s.dy:"slice-dice"===g?1&e.depth?s.dy:s.dx:Math.min(s.dx,s.dy);for(n(h,s.dx*s.dy/e.value),l.area=0;(c=h.length)>0;)l.push(o=h[c-1]),l.area+=o.area,"squarify"!==g||(a=r(l,v))<=p?(h.pop(),p=a):(l.area-=l.pop().area,u(l,v,s,!1),v=Math.min(s.dx,s.dy),l.length=l.area=0,p=1/0);l.length&&(u(l,v,s,!0),l.length=l.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,s=e.y,l=t?c(n.area/t):0;if(t==e.dx){for((r||l>e.dy)&&(l=e.dy);++i<o;)u=n[i],u.x=a,u.y=s,u.dy=l,a+=u.dx=Math.min(e.x+e.dx-a,l?c(u.area/l):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=l,e.dy-=l}else{for((r||l>e.dx)&&(l=e.dx);++i<o;)u=n[i],u.x=a,u.y=s,u.dx=l,s+=u.dy=Math.min(e.y+e.dy-s,l?c(u.area/l):0);u.z=!1,u.dy+=e.y+e.dy-s,e.x+=l,e.dx-=l}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=s[0],i.dy=s[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=Zo.layout.hierarchy(),c=Math.round,s=[1,1],l=null,f=Ni,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));return i.size=function(n){return arguments.length?(s=n,i):s},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ni(t):zi(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return zi(t,n)}if(!arguments.length)return l;var r;return f=null==(l=n)?Ni:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Xu(i,a)},Zo.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=Zo.random.normal.apply(Zo,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=Zo.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},Zo.scale={};var ss={floor:wt,ceil:wt};Zo.scale.linear=function(){return Ui([0,1],[0,1],hu,!1)};var ls={s:1,g:1,p:1,r:1,e:1};Zo.scale.log=function(){return Vi(Zo.scale.linear().domain([0,1]),10,!0,[1,10])};var fs=Zo.format(".0e"),hs={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};Zo.scale.pow=function(){return Xi(Zo.scale.linear(),1,[0,1])},Zo.scale.sqrt=function(){return Zo.scale.pow().exponent(.5)},Zo.scale.ordinal=function(){return Bi([],{t:"range",a:[[]]})},Zo.scale.category10=function(){return Zo.scale.ordinal().range(gs)},Zo.scale.category20=function(){return Zo.scale.ordinal().range(ps)},Zo.scale.category20b=function(){return Zo.scale.ordinal().range(vs)},Zo.scale.category20c=function(){return Zo.scale.ordinal().range(ds)};var gs=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(vt),ps=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(vt),vs=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(vt),ds=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(vt);Zo.scale.quantile=function(){return Wi([],[])},Zo.scale.quantize=function(){return Ji(0,1,[0,1])},Zo.scale.threshold=function(){return Gi([.5],[0,1])},Zo.scale.identity=function(){return Ki([0,1])},Zo.svg={},Zo.svg.arc=function(){function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+ms,a=u.apply(this,arguments)+ms,c=(o>a&&(c=o,o=a,a=c),a-o),s=ba>c?"0":"1",l=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a); - return c>=ys?n?"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"M0,"+n+"A"+n+","+n+" 0 1,0 0,"+-n+"A"+n+","+n+" 0 1,0 0,"+n+"Z":"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":n?"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L"+n*h+","+n*g+"A"+n+","+n+" 0 "+s+",0 "+n*l+","+n*f+"Z":"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L0,0"+"Z"}var t=Qi,e=no,r=to,u=eo;return n.innerRadius=function(e){return arguments.length?(t=bt(e),n):t},n.outerRadius=function(t){return arguments.length?(e=bt(t),n):e},n.startAngle=function(t){return arguments.length?(r=bt(t),n):r},n.endAngle=function(t){return arguments.length?(u=bt(t),n):u},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,i=(r.apply(this,arguments)+u.apply(this,arguments))/2+ms;return[Math.cos(i)*n,Math.sin(i)*n]},n};var ms=-Sa,ys=wa-ka;Zo.svg.line=function(){return ro(wt)};var xs=Zo.map({linear:uo,"linear-closed":io,step:oo,"step-before":ao,"step-after":co,basis:po,"basis-open":vo,"basis-closed":mo,bundle:yo,cardinal:fo,"cardinal-open":so,"cardinal-closed":lo,monotone:So});xs.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Ms=[0,2/3,1/3,0],_s=[0,1/3,2/3,0],bs=[0,1/6,2/3,1/6];Zo.svg.line.radial=function(){var n=ro(ko);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},ao.reverse=co,co.reverse=ao,Zo.svg.area=function(){return Eo(wt)},Zo.svg.area.radial=function(){var n=Eo(ko);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},Zo.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),s=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,s)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,s.r,s.p0)+r(s.r,s.p1,s.a1-s.a0)+u(s.r,s.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)+ms,l=s.call(n,u,r)+ms;return{r:i,a0:o,a1:l,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(l),i*Math.sin(l)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>ba)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=gr,o=pr,a=Ao,c=to,s=eo;return n.radius=function(t){return arguments.length?(a=bt(t),n):a},n.source=function(t){return arguments.length?(i=bt(t),n):i},n.target=function(t){return arguments.length?(o=bt(t),n):o},n.startAngle=function(t){return arguments.length?(c=bt(t),n):c},n.endAngle=function(t){return arguments.length?(s=bt(t),n):s},n},Zo.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=gr,e=pr,r=Co;return n.source=function(e){return arguments.length?(t=bt(e),n):t},n.target=function(t){return arguments.length?(e=bt(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},Zo.svg.diagonal.radial=function(){var n=Zo.svg.diagonal(),t=Co,e=n.projection;return n.projection=function(n){return arguments.length?e(No(t=n)):t},n},Zo.svg.symbol=function(){function n(n,r){return(ws.get(t.call(this,n,r))||To)(e.call(this,n,r))}var t=Lo,e=zo;return n.type=function(e){return arguments.length?(t=bt(e),n):t},n.size=function(t){return arguments.length?(e=bt(t),n):e},n};var ws=Zo.map({circle:To,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*As)),e=t*As;return"M0,"+-t+"L"+e+",0"+" 0,"+t+" "+-e+",0"+"Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/Es),e=t*Es/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/Es),e=t*Es/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});Zo.svg.symbolTypes=ws.keys();var Ss,ks,Es=Math.sqrt(3),As=Math.tan(30*Aa),Cs=[],Ns=0;Cs.call=pa.call,Cs.empty=pa.empty,Cs.node=pa.node,Cs.size=pa.size,Zo.transition=function(n){return arguments.length?Ss?n.transition():n:ma.transition()},Zo.transition.prototype=Cs,Cs.select=function(n){var t,e,r,u=this.id,i=[];n=b(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]);for(var c=this[o],s=-1,l=c.length;++s<l;)(r=c[s])&&(e=n.call(r,r.__data__,s,o))?("__data__"in r&&(e.__data__=r.__data__),Po(e,s,u,r.__transition__[u]),t.push(e)):t.push(null)}return qo(i,u)},Cs.selectAll=function(n){var t,e,r,u,i,o=this.id,a=[];n=w(n);for(var c=-1,s=this.length;++c<s;)for(var l=this[c],f=-1,h=l.length;++f<h;)if(r=l[f]){i=r.__transition__[o],e=n.call(r,r.__data__,f,c),a.push(t=[]);for(var g=-1,p=e.length;++g<p;)(u=e[g])&&Po(u,g,o,i),t.push(u)}return qo(a,o)},Cs.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=R(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return qo(u,this.id)},Cs.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):P(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Cs.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Du:hu,a=Zo.ns.qualify(n);return Ro(this,"attr."+n,t,a.local?i:u)},Cs.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=Zo.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Cs.style=function(n,t,e){function r(){this.style.removeProperty(n)}function u(t){return null==t?r:(t+="",function(){var r,u=Wo.getComputedStyle(this,null).getPropertyValue(n);return u!==t&&(r=hu(u,t),function(t){this.style.setProperty(n,r(t),e)})})}var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(t="");for(e in n)this.style(e,n[e],t);return this}e=""}return Ro(this,"style."+n,t,u)},Cs.styleTween=function(n,t,e){function r(r,u){var i=t.call(this,r,u,Wo.getComputedStyle(this,null).getPropertyValue(n));return i&&function(t){this.style.setProperty(n,i(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,r)},Cs.text=function(n){return Ro(this,"text",n,Do)},Cs.remove=function(){return this.each("end.transition",function(){var n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Cs.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof n&&(n=Zo.ease.apply(Zo,arguments)),P(this,function(e){e.__transition__[t].ease=n}))},Cs.delay=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].delay:P(this,"function"==typeof n?function(e,r,u){e.__transition__[t].delay=+n.call(e,e.__data__,r,u)}:(n=+n,function(e){e.__transition__[t].delay=n}))},Cs.duration=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].duration:P(this,"function"==typeof n?function(e,r,u){e.__transition__[t].duration=Math.max(1,n.call(e,e.__data__,r,u))}:(n=Math.max(1,n),function(e){e.__transition__[t].duration=n}))},Cs.each=function(n,t){var e=this.id;if(arguments.length<2){var r=ks,u=Ss;Ss=e,P(this,function(t,r,u){ks=t.__transition__[e],n.call(t,t.__data__,r,u)}),ks=r,Ss=u}else P(this,function(r){var u=r.__transition__[e];(u.event||(u.event=Zo.dispatch("start","end"))).on(n,t)});return this},Cs.transition=function(){for(var n,t,e,r,u=this.id,i=++Ns,o=[],a=0,c=this.length;c>a;a++){o.push(n=[]);for(var t=this[a],s=0,l=t.length;l>s;s++)(e=t[s])&&(r=Object.create(e.__transition__[u]),r.delay+=r.duration,Po(e,s,i,r)),n.push(e)}return qo(o,i)},Zo.svg.axis=function(){function n(n){n.each(function(){var n,s=Zo.select(this),l=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):wt:t,p=s.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",ka),d=Zo.transition(p.exit()).style("opacity",ka).remove(),m=Zo.transition(p.order()).style("opacity",1),y=Ti(f),x=s.selectAll(".domain").data([0]),M=(x.enter().append("path").attr("class","domain"),Zo.transition(x));v.append("line"),v.append("text");var _=v.select("line"),b=m.select("line"),w=p.select("text").text(g),S=v.select("text"),k=m.select("text");switch(r){case"bottom":n=Uo,_.attr("y2",u),S.attr("y",Math.max(u,0)+o),b.attr("x2",0).attr("y2",u),k.attr("x",0).attr("y",Math.max(u,0)+o),w.attr("dy",".71em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+i+"V0H"+y[1]+"V"+i);break;case"top":n=Uo,_.attr("y2",-u),S.attr("y",-(Math.max(u,0)+o)),b.attr("x2",0).attr("y2",-u),k.attr("x",0).attr("y",-(Math.max(u,0)+o)),w.attr("dy","0em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+-i+"V0H"+y[1]+"V"+-i);break;case"left":n=jo,_.attr("x2",-u),S.attr("x",-(Math.max(u,0)+o)),b.attr("x2",-u).attr("y2",0),k.attr("x",-(Math.max(u,0)+o)).attr("y",0),w.attr("dy",".32em").style("text-anchor","end"),M.attr("d","M"+-i+","+y[0]+"H0V"+y[1]+"H"+-i);break;case"right":n=jo,_.attr("x2",u),S.attr("x",Math.max(u,0)+o),b.attr("x2",u).attr("y2",0),k.attr("x",Math.max(u,0)+o).attr("y",0),w.attr("dy",".32em").style("text-anchor","start"),M.attr("d","M"+i+","+y[0]+"H0V"+y[1]+"H"+i)}if(f.rangeBand){var E=f,A=E.rangeBand()/2;l=f=function(n){return E(n)+A}}else l.rangeBand?l=f:d.call(n,f);v.call(n,l),m.call(n,f)})}var t,e=Zo.scale.linear(),r=zs,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Ls?t+"":zs,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var zs="bottom",Ls={top:1,right:1,bottom:1,left:1};Zo.svg.brush=function(){function n(i){i.each(function(){var i=Zo.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=i.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),i.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=i.selectAll(".resize").data(p,wt);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Ts[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,f=Zo.transition(i),h=Zo.transition(o);c&&(l=Ti(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),e(f)),s&&(l=Ti(s),h.attr("y",l[0]).attr("height",l[1]-l[0]),r(f)),t(f)})}function t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+l[+/e$/.test(n)]+","+f[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",l[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",l[1]-l[0])}function r(n){n.select(".extent").attr("y",f[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",f[1]-f[0])}function u(){function u(){32==Zo.event.keyCode&&(C||(x=null,z[0]-=l[1],z[1]-=f[1],C=2),y())}function p(){32==Zo.event.keyCode&&2==C&&(z[0]+=l[1],z[1]+=f[1],C=0,y())}function v(){var n=Zo.mouse(_),u=!1;M&&(n[0]+=M[0],n[1]+=M[1]),C||(Zo.event.altKey?(x||(x=[(l[0]+l[1])/2,(f[0]+f[1])/2]),z[0]=l[+(n[0]<x[0])],z[1]=f[+(n[1]<x[1])]):x=null),E&&d(n,c,0)&&(e(S),u=!0),A&&d(n,s,1)&&(r(S),u=!0),u&&(t(S),w({type:"brush",mode:C?"move":"resize"}))}function d(n,t,e){var r,u,a=Ti(t),c=a[0],s=a[1],p=z[e],v=e?f:l,d=v[1]-v[0];return C&&(c-=p,s-=d+p),r=(e?g:h)?Math.max(c,Math.min(s,n[e])):n[e],C?u=(r+=p)+d:(x&&(p=Math.max(c,Math.min(s,2*x[e]-r))),r>p?(u=r,r=p):u=p),v[0]!=r||v[1]!=u?(e?o=null:i=null,v[0]=r,v[1]=u,!0):void 0}function m(){v(),S.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),Zo.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),N(),w({type:"brushend"})}var x,M,_=this,b=Zo.select(Zo.event.target),w=a.of(_,arguments),S=Zo.select(_),k=b.datum(),E=!/^(n|s)$/.test(k)&&c,A=!/^(e|w)$/.test(k)&&s,C=b.classed("extent"),N=I(),z=Zo.mouse(_),L=Zo.select(Wo).on("keydown.brush",u).on("keyup.brush",p);if(Zo.event.changedTouches?L.on("touchmove.brush",v).on("touchend.brush",m):L.on("mousemove.brush",v).on("mouseup.brush",m),S.interrupt().selectAll("*").interrupt(),C)z[0]=l[0]-z[0],z[1]=f[0]-z[1];else if(k){var T=+/w$/.test(k),q=+/^n/.test(k);M=[l[1-T]-z[0],f[1-q]-z[1]],z[0]=l[T],z[1]=f[q]}else Zo.event.altKey&&(x=z.slice());S.style("pointer-events","none").selectAll(".resize").style("display",null),Zo.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),v()}var i,o,a=M(n,"brushstart","brush","brushend"),c=null,s=null,l=[0,0],f=[0,0],h=!0,g=!0,p=qs[0];return n.event=function(n){n.each(function(){var n=a.of(this,arguments),t={x:l,y:f,i:i,j:o},e=this.__chart__||t;this.__chart__=t,Ss?Zo.select(this).transition().each("start.brush",function(){i=e.i,o=e.j,l=e.x,f=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=gu(l,t.x),r=gu(f,t.y);return i=o=null,function(u){l=t.x=e(u),f=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){i=t.i,o=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,p=qs[!c<<1|!s],n):c},n.y=function(t){return arguments.length?(s=t,p=qs[!c<<1|!s],n):s},n.clamp=function(t){return arguments.length?(c&&s?(h=!!t[0],g=!!t[1]):c?h=!!t:s&&(g=!!t),n):c&&s?[h,g]:c?h:s?g:null},n.extent=function(t){var e,r,u,a,h;return arguments.length?(c&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),i=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(h=e,e=r,r=h),(e!=l[0]||r!=l[1])&&(l=[e,r])),s&&(u=t[0],a=t[1],c&&(u=u[1],a=a[1]),o=[u,a],s.invert&&(u=s(u),a=s(a)),u>a&&(h=u,u=a,a=h),(u!=f[0]||a!=f[1])&&(f=[u,a])),n):(c&&(i?(e=i[0],r=i[1]):(e=l[0],r=l[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(h=e,e=r,r=h))),s&&(o?(u=o[0],a=o[1]):(u=f[0],a=f[1],s.invert&&(u=s.invert(u),a=s.invert(a)),u>a&&(h=u,u=a,a=h))),c&&s?[[e,u],[r,a]]:c?[e,r]:s&&[u,a])},n.clear=function(){return n.empty()||(l=[0,0],f=[0,0],i=o=null),n},n.empty=function(){return!!c&&l[0]==l[1]||!!s&&f[0]==f[1]},Zo.rebind(n,a,"on")};var Ts={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},qs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Rs=Qa.format=ic.timeFormat,Ds=Rs.utc,Ps=Ds("%Y-%m-%dT%H:%M:%S.%LZ");Rs.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Ho:Ps,Ho.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Ho.toString=Ps.toString,Qa.second=Dt(function(n){return new nc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),Qa.seconds=Qa.second.range,Qa.seconds.utc=Qa.second.utc.range,Qa.minute=Dt(function(n){return new nc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),Qa.minutes=Qa.minute.range,Qa.minutes.utc=Qa.minute.utc.range,Qa.hour=Dt(function(n){var t=n.getTimezoneOffset()/60;return new nc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),Qa.hours=Qa.hour.range,Qa.hours.utc=Qa.hour.utc.range,Qa.month=Dt(function(n){return n=Qa.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),Qa.months=Qa.month.range,Qa.months.utc=Qa.month.utc.range;var Us=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],js=[[Qa.second,1],[Qa.second,5],[Qa.second,15],[Qa.second,30],[Qa.minute,1],[Qa.minute,5],[Qa.minute,15],[Qa.minute,30],[Qa.hour,1],[Qa.hour,3],[Qa.hour,6],[Qa.hour,12],[Qa.day,1],[Qa.day,2],[Qa.week,1],[Qa.month,1],[Qa.month,3],[Qa.year,1]],Hs=Rs.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",we]]),Fs={range:function(n,t,e){return Zo.range(Math.ceil(n/e)*e,+t,e).map(Oo)},floor:wt,ceil:wt};js.year=Qa.year,Qa.scale=function(){return Fo(Zo.scale.linear(),js,Hs)};var Os=js.map(function(n){return[n[0].utc,n[1]]}),Ys=Ds.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",we]]);Os.year=Qa.year.utc,Qa.scale.utc=function(){return Fo(Zo.scale.linear(),Os,Ys)},Zo.text=St(function(n){return n.responseText}),Zo.json=function(n,t){return kt(n,"application/json",Yo,t)},Zo.html=function(n,t){return kt(n,"text/html",Io,t)},Zo.xml=St(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(Zo):"object"==typeof module&&module.exports&&(module.exports=Zo),this.d3=Zo}(); - - - var catalog = -{"packages":[{"name":"v","size":1,"imports":["u"],"cycleSegments":{"u-v":{"s":"v","t":"u"},"v-u":{"s":"u","t":"v"}},"cycleCount":1,"cycleSegmentCount":2},{"name":"u","size":2,"imports":["v"],"cycleSegments":{"u-v":{"s":"v","t":"u"},"v-u":{"s":"u","t":"v"}},"cycleCount":1,"cycleSegmentCount":2},{"name":"b","size":1,"imports":["c"],"cycleSegments":{},"cycleCount":0,"cycleSegmentCount":0},{"name":"c","size":1,"imports":[],"cycleSegments":{},"cycleCount":0,"cycleSegmentCount":0},{"name":"a","size":2,"imports":["b","c"],"cycleSegments":{},"cycleCount":0,"cycleSegmentCount":0},{"name":"n","size":1,"imports":["k"],"cycleSegments":{"k-n":{"s":"n","t":"k"},"l-k":{"s":"k","t":"l"},"n-l":{"s":"l","t":"n"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"}},"cycleCount":2,"cycleSegmentCount":5},{"name":"l","size":1,"imports":["k","n","m"],"cycleSegments":{"k-n":{"s":"n","t":"k"},"k-l":{"s":"l","t":"k"},"l-k":{"s":"k","t":"l"},"n-l":{"s":"l","t":"n"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"}},"cycleCount":3,"cycleSegmentCount":6},{"name":"m","size":1,"imports":["n"],"cycleSegments":{"k-n":{"s":"n","t":"k"},"l-k":{"s":"k","t":"l"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"}},"cycleCount":1,"cycleSegmentCount":4},{"name":"k","size":1,"imports":["l"],"cycleSegments":{"k-n":{"s":"n","t":"k"},"k-l":{"s":"l","t":"k"},"l-k":{"s":"k","t":"l"},"n-l":{"s":"l","t":"n"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"}},"cycleCount":3,"cycleSegmentCount":6},{"name":"z","size":1,"imports":["x"],"cycleSegments":{"z-y":{"s":"y","t":"z"},"y-x":{"s":"x","t":"y"},"x-z":{"s":"z","t":"x"}},"cycleCount":1,"cycleSegmentCount":3},{"name":"y","size":1,"imports":["z"],"cycleSegments":{"z-y":{"s":"y","t":"z"},"y-x":{"s":"x","t":"y"},"x-z":{"s":"z","t":"x"}},"cycleCount":1,"cycleSegmentCount":3},{"name":"x","size":1,"imports":["y"],"cycleSegments":{"z-y":{"s":"y","t":"z"},"y-x":{"s":"x","t":"y"},"x-z":{"s":"z","t":"x"}},"cycleCount":1,"cycleSegmentCount":3}],"cycleSegments":{"k-n":{"s":"n","t":"k"},"z-y":{"s":"y","t":"z"},"y-x":{"s":"x","t":"y"},"k-l":{"s":"l","t":"k"},"l-k":{"s":"k","t":"l"},"n-l":{"s":"l","t":"n"},"u-v":{"s":"v","t":"u"},"v-u":{"s":"u","t":"v"},"m-l":{"s":"l","t":"m"},"n-m":{"s":"m","t":"n"},"x-z":{"s":"z","t":"x"}},"summary":{"packages":12,"sources":14,"cycles":5,"cycleSegments":11}} - ; - - var diameter = 1000, - radius = diameter / 2, - innerRadius = radius - 300; - - var cluster = d3.layout.cluster() - .size([360, innerRadius]) - .sort(null) - .value(function(d) { return d.size; }); - - var bundle = d3.layout.bundle(); - - var line = d3.svg.line.radial() - .interpolate("bundle") - .tension(.75) - .radius(function(d) { return d.y; }) - .angle(function(d) { return d.x / 180 * Math.PI; }); - - var svg = d3.select("body").append("svg") - .attr("width", diameter) - .attr("height", diameter) - .append("g") - .attr("transform", "translate(" + radius + "," + radius + ")"); - - var link = svg.append("g").selectAll(".link"), - node = svg.append("g").selectAll(".node"), - cycles = {}, highlightCycles, selectedNode; - - function isCyclicLink(l) { - return highlightCycles && - (cycles[l.source.key + "-" + l.target.key] || cycles[l.target.key + "-" + l.source.key]); - } - - function isCyclicPackageLink(l, p) { - var key = l.source.key + "-" + l.target.key, - rKey = l.target.key + "-" + l.source.key; - return isCyclicLink(l) && (p.cycleSegments[key] || p.cycleSegments[rKey]); - } - - function refreshPaths() { - svg.selectAll("path.link").classed("link--cycle", isCyclicLink); - } - - function processCatalog() { - var nodes = cluster.nodes(packageHierarchy(catalog.packages)), - links = packageImports(nodes), - splines = bundle(links); - cycles = catalog.cycleSegments; - - d3.select("input[type=checkbox]").on("change", function() { - highlightCycles = this.checked; - refreshPaths(); - }); - - link = link - .data(splines) - .enter().append("path") - .each(function(d) { d.source = d[0], d.target = d[d.length - 1]; }) - .attr("class", "link") - .classed("link--cycle", isCyclicLink) - .attr("d", function(d, i) { return line(splines[i]); }); - - - node = node - .data(nodes.filter(function(n) { return !n.children; })) - .enter().append("text") - .attr("class", "node") - .attr("dy", ".31em") - .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" + (d.x < 180 ? "" : "rotate(180)"); }) - .style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; }) - .text(function(d) { return d.key; }) - .on("focus", processSelect) - .on("blur", processSelect); - - d3.select("input[type=range]").on("change", function() { - line.tension(this.value / 100); - svg.selectAll("path.link") - .data(splines) - .attr("d", function(d, i) { return line(splines[i]); }); - }); - - d3.select("#packageCount").text(catalog.summary.packages); - d3.select("#sourceCount").text(catalog.summary.sources); - d3.select("#segmentCount").text(catalog.summary.cycleSegments); - d3.select("#cycleCount").text(catalog.summary.cycles); - } - - function processSelect(d) { - if (selectedNode === d) { - deselected(d); - selectedNode = null; - - } else if (selectedNode) { - deselected(selectedNode); - selectedNode = null; - selected(d); - - } else { - selected(d); - selectedNode = d; - } - } - - function selected(d) { - node - .each(function(n) { n.target = n.source = false; }) - .classed("node--focus", function(n) { return n === d; }); - - link - .classed("link--cycle", function(l) { return isCyclicPackageLink(l, d); }) - .classed("link--target", function(l) { if (l.target === d) return l.source.source = true; }) - .classed("link--source", function(l) { if (l.source === d) return l.target.target = true; }) - .filter(function(l) { return l.target === d || l.source === d; }) - .each(function() { this.parentNode.appendChild(this); }); - - node - .classed("node--target", function(n) { return n.target; }) - .classed("node--source", function(n) { return n.source; }); - - d3.select("#psourceCount").text(d.size); - d3.select("#pdependentCount").text(d.imports.length); - d3.select("#psegmentCount").text(d.cycleSegmentCount); - d3.select("#pcycleCount").text(d.cycleCount); - d3.select(".details").classed("shown", function() { return true; }); - } - - function deselected(d) { - link - .classed("link--cycle", isCyclicLink) - .classed("link--target", false) - .classed("link--source", false); - - node - .classed("node--target", false) - .classed("node--source", false) - .classed("node--focus", false); - d3.select(".details").classed("shown", function() { return false; }); - } - - d3.select(self.frameElement).style("height", diameter + "px"); - - // Lazily construct the package hierarchy. - function packageHierarchy(packages) { - var map = {}, cnt = 0; - - // Builds the structure top-down to the specified leaf or until - // another leaf in which case hook this leaf to the same parent - function buildHierarchy(leaf, i) { - var leafName = leaf.name, - node, name, parent = map[""], start = 0; - while (start < leafName.length) { - name = parentName(leafName, start); - node = map[name]; - if (!node) { - node = map[name] = parentNode(name, parent); - parent.children.push(node); - - } else if (node.imports) { - leaf.parent = parent; - parent.children.push(leaf); - break; - } - parent = node; - start = name.length + 1; - } - } - - function parentNode(name, parent) { - return {name: name, parent: parent, key: name, children: []}; - } - - function parentName(leafName, start) { - var i = leafName.indexOf(".", start); - return i > 0 ? leafName.substring(0, i) : leafName; - } - - // First populate all packages as leafs - packages.forEach(function(d) { - map[d.name] = d; - d.key = d.name; - }); - - // Next synthesize the intermediate structure, by-passing any leafs - map[""] = parentNode("", null); - var i = 0; - packages.forEach(function(d) { - buildHierarchy(d, i++); - }); - - return map[""]; - } - - // Return a list of imports for the given array of nodes. - function packageImports(nodes) { - var map = {}, - imports = []; - - // Compute a map from name to node. - nodes.forEach(function(d) { - map[d.name] = d; - }); - - // For each import, construct a link from the source to target node. - nodes.forEach(function(d) { - if (d.imports) d.imports.forEach(function(i) { - imports.push({source: map[d.name], target: map[i]}); - }); - }); - - return imports; - } - - processCatalog(); -</script> -</body> -</html> diff --git a/framework/src/onos/utils/jnc/pom.xml b/framework/src/onos/utils/jnc/pom.xml deleted file mode 100644 index 3fd83b3d..00000000 --- a/framework/src/onos/utils/jnc/pom.xml +++ /dev/null @@ -1,102 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-jnc-osgi</artifactId> - <packaging>bundle</packaging> - - <description>TailF JNC and Ganymed SSH2 packaged as OSGi bundle</description> - - <dependencies> - <dependency> - <groupId>ch.ethz.ganymed</groupId> - <artifactId>ganymed-ssh2</artifactId> - <version>262</version> - </dependency> - - <dependency> - <!-- TODO: change this appropriately when the official TailF JNC is available --> - <groupId>org.onosproject</groupId> - <artifactId>jnc</artifactId> - <version>1.0</version> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-shade-plugin</artifactId> - <version>2.3</version> - <configuration> - <filters> - <filter> - <artifact>com.google.guava:guava</artifact> - <excludes> - <exclude>**</exclude> - </excludes> - </filter> - </filters> - </configuration> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>shade</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <configuration> - <instructions> - <Export-Package> - com.tailf.jnc, - ch.ethz.ssh2, - ch.ethz.ssh2.auth, - ch.ethz.ssh2.channel, - ch.ethz.ssh2.crypto, - ch.ethz.ssh2.crypto.cipher, - ch.ethz.ssh2.crypto.dh, - ch.ethz.ssh2.crypto.digest, - ch.ethz.ssh2.log, - ch.ethz.ssh2.packets, - ch.ethz.ssh2.server, - ch.ethz.ssh2.sftp, - ch.ethz.ssh2.signature, - ch.ethz.ssh2.transport, - ch.ethz.ssh2.util - </Export-Package> - </instructions> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/framework/src/onos/utils/junit/pom.xml b/framework/src/onos/utils/junit/pom.xml deleted file mode 100644 index da99f46d..00000000 --- a/framework/src/onos/utils/junit/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-junit</artifactId> - <packaging>bundle</packaging> - - <description>ON.Lab JUnit test utilities</description> - - <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava-testlib</artifactId> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest-core</artifactId> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest-library</artifactId> - <scope>compile</scope> - </dependency> - </dependencies> - -</project> diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/ExceptionTest.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/ExceptionTest.java deleted file mode 100644 index 09b3fe37..00000000 --- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/ExceptionTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.junit; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; - -/** - * Base for exception tests. - */ -public abstract class ExceptionTest { - - protected static final Throwable CAUSE = new RuntimeException("boom"); - protected static final String MESSAGE = "Uh oh.... boom"; - - protected abstract Exception getDefault(); - protected abstract Exception getWithMessage(); - protected abstract Exception getWithMessageAndCause(); - - @Test - public void noMessageNoCause() { - Exception e = getDefault(); - assertEquals("incorrect message", null, e.getMessage()); - assertEquals("incorrect cause", null, e.getCause()); - } - - @Test - public void withMessage() { - Exception e = getWithMessage(); - assertEquals("incorrect message", MESSAGE, e.getMessage()); - assertEquals("incorrect cause", null, e.getCause()); - } - - @Test - public void withCause() { - Exception e = getWithMessageAndCause(); - assertEquals("incorrect message", MESSAGE, e.getMessage()); - assertSame("incorrect cause", CAUSE, e.getCause()); - } -} diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/ImmutableClassChecker.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/ImmutableClassChecker.java deleted file mode 100644 index 80aa2cb1..00000000 --- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/ImmutableClassChecker.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.junit; - -import org.hamcrest.Description; -import org.hamcrest.StringDescription; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -/** - * Hamcrest style class for verifying that a class follows the - * accepted rules for immutable classes. - * - * The rules that are enforced for immutable classes: - * - the class must be declared final - * - all data members of the class must be declared private and final - * - the class must not define any setter methods - */ - -public class ImmutableClassChecker { - - private String failureReason = ""; - - /** - * Method to determine if a given class is a properly specified - * immutable class. - * - * @param clazz the class to check - * @return true if the given class is a properly specified immutable class. - */ - private boolean isImmutableClass(Class<?> clazz, boolean allowNonFinalClass) { - // class must be declared final - if (!allowNonFinalClass && !Modifier.isFinal(clazz.getModifiers())) { - failureReason = "a class that is not final"; - return false; - } - - // class must have only final and private data members - for (final Field field : clazz.getDeclaredFields()) { - if (field.getName().startsWith("_") || - field.getName().startsWith("$")) { - // eclipse generated code may insert switch table - ignore - // cobertura sticks these fields into classes - ignore them - continue; - } - if (!Modifier.isFinal(field.getModifiers())) { - failureReason = "a field named '" + field.getName() + - "' that is not final"; - return false; - } - if (!Modifier.isPrivate(field.getModifiers())) { - // - // NOTE: We relax the recommended rules for defining immutable - // objects and allow "static final" fields that are not - // private. The "final" check was already done above so we - // don't repeat it here. - // - if (!Modifier.isStatic(field.getModifiers())) { - failureReason = "a field named '" + field.getName() + - "' that is not private and is not static"; - return false; - } - } - } - - // class must not define any setters - for (final Method method : clazz.getMethods()) { - if (method.getDeclaringClass().equals(clazz)) { - if (method.getName().startsWith("set")) { - failureReason = "a class with a setter named '" + method.getName() + "'"; - return false; - } - } - } - - return true; - } - - /** - * Describe why an error was reported. Uses Hamcrest style Description - * interfaces. - * - * @param description the Description object to use for reporting the - * mismatch - */ - public void describeMismatch(Description description) { - description.appendText(failureReason); - } - - /** - * Describe the source object that caused an error, using a Hamcrest - * Matcher style interface. In this case, it always returns - * that we are looking for a properly defined utility class. - * - * @param description the Description object to use to report the "to" - * object - */ - public void describeTo(Description description) { - description.appendText("a properly defined immutable class"); - } - - /** - * Assert that the given class adheres to the immutable class rules. - * - * @param clazz the class to check - * - * @throws java.lang.AssertionError if the class is not an - * immutable class - */ - public static void assertThatClassIsImmutable(Class<?> clazz) { - final ImmutableClassChecker checker = new ImmutableClassChecker(); - if (!checker.isImmutableClass(clazz, false)) { - final Description toDescription = new StringDescription(); - final Description mismatchDescription = new StringDescription(); - - checker.describeTo(toDescription); - checker.describeMismatch(mismatchDescription); - final String reason = - "\n" + - "Expected: is \"" + toDescription.toString() + "\"\n" + - " but : was \"" + mismatchDescription.toString() + "\""; - - throw new AssertionError(reason); - } - } - - /** - * Assert that the given class adheres to the immutable class rules, but - * is not declared final. Classes that need to be inherited from cannot be - * declared final. - * - * @param clazz the class to check - * - * @throws java.lang.AssertionError if the class is not an - * immutable class - */ - public static void assertThatClassIsImmutableBaseClass(Class<?> clazz) { - final ImmutableClassChecker checker = new ImmutableClassChecker(); - if (!checker.isImmutableClass(clazz, true)) { - final Description toDescription = new StringDescription(); - final Description mismatchDescription = new StringDescription(); - - checker.describeTo(toDescription); - checker.describeMismatch(mismatchDescription); - final String reason = - "\n" + - "Expected: is \"" + toDescription.toString() + "\"\n" + - " but : was \"" + mismatchDescription.toString() + "\""; - - throw new AssertionError(reason); - } - } -} diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/IntegrationTest.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/IntegrationTest.java deleted file mode 100644 index a033802f..00000000 --- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/IntegrationTest.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.junit; - -/** - * Marker interface used to separate unit tests from integration tests. All - * integration tests should be marked with: - * {@literal @Category}(IntegrationTest.class) - * so that they can be run separately. - */ -public interface IntegrationTest { -} diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/NullScheduledExecutor.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/NullScheduledExecutor.java deleted file mode 100644 index 6d959703..00000000 --- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/NullScheduledExecutor.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.junit; - -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * A scheduled executor service that does not do any of the work scheduled to it. - * <p> - * This is useful for testing when you want to disable a background scheduled - * task. - * </p> - */ -public class NullScheduledExecutor implements ScheduledExecutorService { - @Override - public ScheduledFuture<?> schedule(Runnable command, long delay, - TimeUnit unit) { - return null; - } - - @Override - public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, - TimeUnit unit) { - return null; - } - - @Override - public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, - long initialDelay, - long period, TimeUnit unit) { - return null; - } - - @Override - public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, - long initialDelay, - long delay, - TimeUnit unit) { - return null; - } - - @Override - public void shutdown() { - - } - - @Override - public List<Runnable> shutdownNow() { - return null; - } - - @Override - public boolean isShutdown() { - return false; - } - - @Override - public boolean isTerminated() { - return false; - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit unit) - throws InterruptedException { - return false; - } - - @Override - public <T> Future<T> submit(Callable<T> task) { - return null; - } - - @Override - public <T> Future<T> submit(Runnable task, T result) { - return null; - } - - @Override - public Future<?> submit(Runnable task) { - return null; - } - - @Override - public <T> List<Future<T>> invokeAll( - Collection<? extends Callable<T>> tasks) - throws InterruptedException { - return null; - } - - @Override - public <T> List<Future<T>> invokeAll( - Collection<? extends Callable<T>> tasks, long timeout, - TimeUnit unit) throws InterruptedException { - return null; - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> tasks) - throws InterruptedException, ExecutionException { - return null; - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> tasks, - long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - return null; - } - - @Override - public void execute(Runnable command) { - - } -} diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestTools.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestTools.java deleted file mode 100644 index 40e8686c..00000000 --- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestTools.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.junit; - -import com.google.common.collect.ImmutableList; -import com.google.common.io.Files; - -import java.io.File; -import java.io.IOException; -import java.net.ServerSocket; -import java.util.List; -import java.util.Random; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.junit.Assert.fail; - -/** - * Utilities to aid in producing JUnit tests. - */ -public final class TestTools { - - private static final Random RANDOM = new Random(); - - // Prohibit construction - private TestTools() { - } - - public static void print(String msg) { - System.out.print(msg); - } - - /** - * Suspends the current thread for a specified number of millis. - * - * @param ms number of millis - */ - public static void delay(int ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - fail("test interrupted"); - } - } - - /** - * Returns the current time in millis since epoch. - * - * @return current time - */ - public static long now() { - return System.currentTimeMillis(); - } - - /** - * Runs the specified runnable until it completes successfully or until the - * specified time expires. If the latter occurs, the first encountered - * assertion on the last attempt will be re-thrown. Errors other than - * assertion errors will be propagated immediately. - * <p> - * Assertions attempts will not be closer than 10 millis apart and no - * further than 50 millis. - * </p> - * - * @param delay number of millis to delay before the first attempt - * @param duration number of milliseconds beyond the current time - * @param assertions test assertions runnable - */ - public static void assertAfter(int delay, int duration, Runnable assertions) { - checkArgument(delay < duration, "delay >= duration"); - long start = now(); - int step = Math.max(Math.min((duration - delay) / 100, 50), 10); - - // Is there an initial delay? - if (delay > 0) { - delay(delay); - } - - // Keep going until the assertions succeed or until time runs-out. - while (true) { - try { - assertions.run(); - break; - } catch (AssertionError e) { - // If there was an error and time ran out, re-throw it. - if (now() - start > duration) { - throw e; - } - } - delay(step); - } - } - - /** - * Runs the specified runnable until it completes successfully or until the - * specified time expires. If the latter occurs, the first encountered - * assertion on the last attempt will be re-thrown. Errors other than - * assertion errors will be propagated immediately. - * <p> - * Assertions attempts will not be closer than 10 millis apart and no - * further than 50 millis. - * </p> - * - * @param duration number of milliseconds beyond the current time - * @param assertions test assertions runnable - */ - public static void assertAfter(int duration, Runnable assertions) { - assertAfter(0, duration, assertions); - } - - - /** - * Creates a directory tree of test files. To signify creating a directory - * file path should end with '/'. - * - * @param paths list of file paths - * @return list of created files - * @throws java.io.IOException if there is an issue - */ - public static List<File> createTestFiles(List<String> paths) throws IOException { - return createTestFiles(paths, 32, 1024); - } - - /** - * Creates a directory tree of test files. To signify creating a directory - * file path should end with '/'. - * - * @param paths list of file paths - * @param minSize minimum file size in bytes - * @param maxSize maximum file size in bytes - * @return list of created files - * @throws java.io.IOException if there is an issue - */ - public static List<File> createTestFiles(List<String> paths, - int minSize, int maxSize) throws IOException { - ImmutableList.Builder<File> files = ImmutableList.builder(); - for (String p : paths) { - File f = new File(p); - if (p.endsWith("/")) { - if (f.mkdirs()) { - files.add(f); - } - } else { - Files.createParentDirs(f); - if (f.createNewFile()) { - writeRandomFile(f, minSize, maxSize); - files.add(f); - } - } - } - return files.build(); - } - - /** - * Writes random binary content into the specified file. The number of - * bytes will be random between the given minimum and maximum. - * - * @param file file to write data to - * @param minSize minimum number of bytes to write - * @param maxSize maximum number of bytes to write - * @throws IOException if there is an issue - */ - public static void writeRandomFile(File file, int minSize, int maxSize) throws IOException { - int size = minSize + (minSize == maxSize ? 0 : RANDOM.nextInt(maxSize - minSize)); - byte[] data = new byte[size]; - tweakBytes(RANDOM, data, size / 4); - Files.write(data, file); - } - - - /** - * Tweaks the given number of bytes in a byte array. - * - * @param random random number generator - * @param data byte array to be tweaked - * @param count number of bytes to tweak - */ - public static void tweakBytes(Random random, byte[] data, int count) { - tweakBytes(random, data, count, 0, data.length); - } - - /** - * Tweaks the given number of bytes in the specified range of a byte array. - * - * @param random random number generator - * @param data byte array to be tweaked - * @param count number of bytes to tweak - * @param start index at beginning of range (inclusive) - * @param end index at end of range (exclusive) - */ - public static void tweakBytes(Random random, byte[] data, int count, - int start, int end) { - int len = end - start; - for (int i = 0; i < count; i++) { - data[start + random.nextInt(len)] = (byte) random.nextInt(); - } - } - - /* - * Finds an available port that a test can bind to. - */ - public static int findAvailablePort(int defaultPort) { - try { - ServerSocket socket = new ServerSocket(0); - socket.setReuseAddress(true); - int port = socket.getLocalPort(); - socket.close(); - return port; - } catch (IOException ex) { - return defaultPort; - } - } - - -} diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestUtils.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestUtils.java deleted file mode 100644 index 686a9a59..00000000 --- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/TestUtils.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.junit; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - - -/** - * Utilities for testing. - */ -public final class TestUtils { - - /** - * Sets the field, bypassing scope restriction. - * - * @param subject Object where the field belongs - * @param fieldName name of the field to set - * @param value value to set to the field. - * @param <T> subject type - * @param <U> value type - * @throws TestUtilsException if there are reflection errors while setting - * the field - */ - public static <T, U> void setField(T subject, String fieldName, U value) - throws TestUtilsException { - @SuppressWarnings("unchecked") - Class clazz = subject.getClass(); - try { - while (clazz != null) { - try { - Field field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - field.set(subject, value); - break; - } catch (NoSuchFieldException ex) { - if (clazz == clazz.getSuperclass()) { - break; - } - clazz = clazz.getSuperclass(); - } - } - } catch (SecurityException | IllegalArgumentException | - IllegalAccessException e) { - throw new TestUtilsException("setField failed", e); - } - } - - /** - * Gets the field, bypassing scope restriction. - * - * @param subject Object where the field belongs - * @param fieldName name of the field to get - * @param <T> subject type - * @param <U> fieldO value type - * @return value of the field. - * @throws TestUtilsException if there are reflection errors while getting - * the field - */ - public static <T, U> U getField(T subject, String fieldName) - throws TestUtilsException { - try { - NoSuchFieldException exception = null; - @SuppressWarnings("unchecked") - Class clazz = subject.getClass(); - while (clazz != null) { - try { - Field field = clazz.getDeclaredField(fieldName); - field.setAccessible(true); - - @SuppressWarnings("unchecked") - U result = (U) field.get(subject); - return result; - } catch (NoSuchFieldException e) { - exception = e; - if (clazz == clazz.getSuperclass()) { - break; - } - clazz = clazz.getSuperclass(); - } - } - throw new TestUtilsException("Field not found. " + fieldName, exception); - - } catch (SecurityException | - IllegalArgumentException | IllegalAccessException e) { - throw new TestUtilsException("getField failed", e); - } - } - - /** - * Calls the method, bypassing scope restriction. - * - * @param subject Object where the method belongs - * @param methodName name of the method to call - * @param paramTypes formal parameter type array - * @param args arguments - * @return return value or null if void - * @param <T> subject type - * @param <U> return value type - * @throws TestUtilsException if there are reflection errors while calling - * the method - */ - public static <T, U> U callMethod(T subject, String methodName, - Class<?>[] paramTypes, Object...args) throws TestUtilsException { - - try { - @SuppressWarnings("unchecked") - Class<T> clazz = (Class<T>) subject.getClass(); - final Method method; - if (paramTypes == null || paramTypes.length == 0) { - method = clazz.getDeclaredMethod(methodName); - } else { - method = clazz.getDeclaredMethod(methodName, paramTypes); - } - method.setAccessible(true); - - @SuppressWarnings("unchecked") - U result = (U) method.invoke(subject, args); - return result; - } catch (NoSuchMethodException | SecurityException | - IllegalAccessException | IllegalArgumentException | - InvocationTargetException e) { - throw new TestUtilsException("callMethod failed", e); - } - } - - /** - * Calls the method, bypassing scope restriction. - * - * @param subject Object where the method belongs - * @param methodName name of the method to call - * @param paramType formal parameter type - * @param arg argument - * @return return value or null if void - * @param <T> subject type - * @param <U> return value type - * @throws TestUtilsException if there are reflection errors while calling - * the method - */ - public static <T, U> U callMethod(T subject, String methodName, - Class<?> paramType, Object arg) throws TestUtilsException { - return callMethod(subject, methodName, new Class<?>[]{paramType}, arg); - } - - /** - * Triggers an allocation of an object of type T and forces a call to - * the private constructor. - * - * @param constructor Constructor to call - * @param <T> type of the object to create - * @return created object of type T - * @throws TestUtilsException if there are reflection errors while calling - * the constructor - */ - public static <T> T callConstructor(Constructor<T> constructor) - throws TestUtilsException { - try { - constructor.setAccessible(true); - return constructor.newInstance(); - } catch (InstantiationException | IllegalAccessException | - InvocationTargetException error) { - throw new TestUtilsException("callConstructor failed", error); - } - } - - /** - * Avoid instantiation. - */ - private TestUtils() {} - - /** - * Exception that can be thrown if problems are encountered while executing - * the utility method. These are usually problems accessing fields/methods - * through reflection. The original exception can be found by examining the - * cause. - */ - public static class TestUtilsException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs a new exception with the specified detail message and - * cause. - * - * @param message the detail message - * @param cause the original cause of this exception - */ - public TestUtilsException(String message, Throwable cause) { - super(message, cause); - } - } -} diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/UtilityClassChecker.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/UtilityClassChecker.java deleted file mode 100644 index 9c623cee..00000000 --- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/UtilityClassChecker.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.junit; - -import org.hamcrest.Description; -import org.hamcrest.StringDescription; -import org.onlab.junit.TestUtils.TestUtilsException; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - - -/** - * Hamcrest style class for verifying that a class follows the - * accepted rules for utility classes. - * - * The rules that are enforced for utility classes: - * - the class must be declared final - * - the class must have only one constructor - * - the constructor must be private and inaccessible to callers - * - the class must have only static methods - */ - -public class UtilityClassChecker { - - private String failureReason = ""; - - /** - * Method to determine if a given class is a properly specified - * utility class. In addition to checking that the class meets the criteria - * for utility classes, an object of the class type is allocated to force - * test code coverage onto the class constructor. - * - * @param clazz the class to check - * @return true if the given class is a properly specified utility class. - */ - private boolean isProperlyDefinedUtilityClass(Class<?> clazz) { - // class must be declared final - if (!Modifier.isFinal(clazz.getModifiers())) { - failureReason = "a class that is not final"; - return false; - } - - // class must have only one constructor - final Constructor<?>[] constructors = clazz.getDeclaredConstructors(); - if (constructors.length != 1) { - failureReason = "a class with more than one constructor"; - return false; - } - - // constructor must not be accessible outside of the class - final Constructor<?> constructor = constructors[0]; - if (constructor.isAccessible()) { - failureReason = "a class with an accessible default constructor"; - return false; - } - - // constructor must be private - if (!Modifier.isPrivate(constructor.getModifiers())) { - failureReason = "a class with a default constructor that is not private"; - return false; - } - - // class must have only static methods - for (final Method method : clazz.getMethods()) { - if (method.getDeclaringClass().equals(clazz)) { - if (!Modifier.isStatic(method.getModifiers())) { - failureReason = "a class with one or more non-static methods"; - return false; - } - } - - } - - try { - final Object newObject = TestUtils.callConstructor(constructor); - if (newObject == null) { - failureReason = "could not instantiate a new object"; - return false; - } - } catch (TestUtilsException e) { - failureReason = "could not instantiate a new object"; - return false; - } - return true; - } - - /** - * Describe why an error was reported. Uses Hamcrest style Description - * interfaces. - * - * @param description the Description object to use for reporting the - * mismatch - */ - public void describeMismatch(Description description) { - description.appendText(failureReason); - } - - /** - * Describe the source object that caused an error, using a Hamcrest - * Matcher style interface. In this case, it always returns - * that we are looking for a properly defined utility class. - * - * @param description the Description object to use to report the "to" - * object - */ - public void describeTo(Description description) { - description.appendText("a properly defined utility class"); - } - - /** - * Assert that the given class adheres to the utility class rules. - * - * @param clazz the class to check - * - * @throws java.lang.AssertionError if the class is not a valid - * utility class - */ - public static void assertThatClassIsUtility(Class<?> clazz) { - final UtilityClassChecker checker = new UtilityClassChecker(); - if (!checker.isProperlyDefinedUtilityClass(clazz)) { - final Description toDescription = new StringDescription(); - final Description mismatchDescription = new StringDescription(); - - checker.describeTo(toDescription); - checker.describeMismatch(mismatchDescription); - final String reason = - "\n" + - "Expected: is \"" + toDescription.toString() + "\"\n" + - " but : was \"" + mismatchDescription.toString() + "\""; - - throw new AssertionError(reason); - } - } -} diff --git a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/package-info.java b/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/package-info.java deleted file mode 100644 index 379e4a04..00000000 --- a/framework/src/onos/utils/junit/src/main/java/org/onlab/junit/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Utilities to assist in developing JUnit tests. - */ -package org.onlab.junit; diff --git a/framework/src/onos/utils/junit/src/main/resources/org/onosproject/openflow/controller/impl/ControllerTestKeystore.jks b/framework/src/onos/utils/junit/src/main/resources/org/onosproject/openflow/controller/impl/ControllerTestKeystore.jks Binary files differdeleted file mode 100644 index ba750519..00000000 --- a/framework/src/onos/utils/junit/src/main/resources/org/onosproject/openflow/controller/impl/ControllerTestKeystore.jks +++ /dev/null diff --git a/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/ImmutableClassCheckerTest.java b/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/ImmutableClassCheckerTest.java deleted file mode 100644 index cd5a8c1a..00000000 --- a/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/ImmutableClassCheckerTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.junit; - -import org.junit.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; - -/** - * Set of unit tests to check the implementation of the immutable class - * checker. - */ -public class ImmutableClassCheckerTest { - /** - * Test class for non final class check. - */ - // CHECKSTYLE IGNORE FinalClass FOR NEXT 1 LINES - static class NonFinal { - private NonFinal() { } - } - - /** - * Check that a non final class correctly produces an error. - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testNonFinalClass() throws Exception { - boolean gotException = false; - try { - assertThatClassIsImmutable(NonFinal.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("is not final")); - gotException = true; - } - assertThat(gotException, is(true)); - } - - /** - * Test class for non private member class check. - */ - static final class FinalProtectedMember { - protected final int x = 0; - } - - /** - * Check that a final class with a non-private member is properly detected. - * - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testFinalProtectedMember() throws Exception { - boolean gotException = false; - try { - assertThatClassIsImmutable(FinalProtectedMember.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("a field named 'x' that is not private")); - gotException = true; - } - assertThat(gotException, is(true)); - } - - /** - * Test class for non private member class check. - */ - static final class NotFinalPrivateMember { - private int x = 0; - } - - /** - * Check that a final class with a non-final private - * member is properly detected. - * - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testNotFinalPrivateMember() throws Exception { - boolean gotException = false; - try { - assertThatClassIsImmutable(NotFinalPrivateMember.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("a field named 'x' that is not final")); - gotException = true; - } - assertThat(gotException, is(true)); - } - - /** - * Test class for non private member class check. - */ - static final class ClassWithSetter { - private final int x = 0; - public void setX(int newX) { - } - } - - /** - * Check that a final class with a final private - * member that is modifyable by a setter is properly detected. - * - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testClassWithSetter() throws Exception { - boolean gotException = false; - try { - assertThatClassIsImmutable(ClassWithSetter.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("a class with a setter named 'setX'")); - gotException = true; - } - assertThat(gotException, is(true)); - } - -} - diff --git a/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/TestToolsTest.java b/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/TestToolsTest.java deleted file mode 100644 index d11cea0b..00000000 --- a/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/TestToolsTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.junit; - -import org.junit.Test; - -import static org.junit.Assert.*; -import static org.onlab.junit.TestTools.assertAfter; - -public class TestToolsTest { - - @Test - public void testSuccess() { - assertAfter(10, 100, new Runnable() { - int count = 0; - @Override - public void run() { - if (count++ < 3) { - assertTrue(false); - } - } - }); - } - - @Test(expected = AssertionError.class) - public void testFailure() { - assertAfter(100, new Runnable() { - @Override - public void run() { - assertTrue(false); - } - }); - } -} diff --git a/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/TestUtilsTest.java b/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/TestUtilsTest.java deleted file mode 100644 index 68e407fc..00000000 --- a/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/TestUtilsTest.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.junit; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import org.junit.Before; -import org.junit.Test; -import org.onlab.junit.TestUtils.TestUtilsException; - -/** - * Test and usage examples for TestUtils. - */ -public class TestUtilsTest { - - /** - * Test data. - */ - private static final class TestClass { - - @SuppressWarnings("unused") - private int privateField = 42; - - @SuppressWarnings("unused") - protected int protectedField = 2501; // CHECKSTYLE IGNORE THIS LINE - - /** - * Protected method with multiple argument. - * - * @param x simply returns - * @param y not used - * @return x - */ - @SuppressWarnings("unused") - private int privateMethod(Number x, Long y) { - return x.intValue(); - } - - /** - * Protected method with no argument. - * - * @return int - */ - @SuppressWarnings("unused") - protected int protectedMethod() { - return 42; - } - - /** - * Method returning array. - * - * @param ary random array - * @return ary - */ - @SuppressWarnings("unused") - private int[] arrayReturnMethod(int[] ary) { - return ary; - } - - /** - * Method without return value. - * - * @param s ignored - */ - @SuppressWarnings("unused") - private void voidMethod(String s) { - System.out.println(s); - } - } - - private TestClass test; - - /** - * Sets up the test fixture. - */ - @Before - public void setUp() { - test = new TestClass(); - } - - /** - * Example to access private field. - * - * @throws TestUtilsException TestUtils error - */ - @Test - public void testSetGetPrivateField() throws TestUtilsException { - - assertEquals(42, (int) TestUtils.getField(test, "privateField")); - TestUtils.setField(test, "privateField", 0xDEAD); - assertEquals(0xDEAD, (int) TestUtils.getField(test, "privateField")); - } - - /** - * Example to access protected field. - * - * @throws TestUtilsException TestUtils error - */ - @Test - public void testSetGetProtectedField() throws TestUtilsException { - - assertEquals(2501, (int) TestUtils.getField(test, "protectedField")); - TestUtils.setField(test, "protectedField", 0xBEEF); - assertEquals(0xBEEF, (int) TestUtils.getField(test, "protectedField")); - } - - /** - * Example to call private method and multiple parameters. - * <p/> - * It also illustrates that paramTypes must match declared type, - * not the runtime types of arguments. - * - * @throws TestUtilsException TestUtils error - */ - @Test - public void testCallPrivateMethod() throws TestUtilsException { - - int result = TestUtils.callMethod(test, "privateMethod", - new Class<?>[] {Number.class, Long.class}, - Long.valueOf(42), Long.valueOf(32)); - assertEquals(42, result); - } - - /** - * Example to call protected method and no parameters. - * - * @throws TestUtilsException TestUtils error - */ - @Test - public void testCallProtectedMethod() throws TestUtilsException { - - int result = TestUtils.callMethod(test, "protectedMethod", - new Class<?>[] {}); - assertEquals(42, result); - } - - /** - * Example to call method returning array. - * <p/> - * Note: It is not required to receive as Object. - * Following is just verifying it is not Boxed arrays. - * - * @throws TestUtilsException TestUtils error - */ - @Test - public void testCallArrayReturnMethod() throws TestUtilsException { - - int[] array = {1, 2, 3}; - Object aryResult = TestUtils.callMethod(test, "arrayReturnMethod", - new Class<?>[] {int[].class}, array); - assertEquals(int[].class, aryResult.getClass()); - assertArrayEquals(array, (int[]) aryResult); - } - - - /** - * Example to call void returning method. - * <p/> - * Note: Return value will be null for void methods. - * - * @throws TestUtilsException TestUtils error - */ - @Test - public void testCallVoidReturnMethod() throws TestUtilsException { - - Object voidResult = TestUtils.callMethod(test, "voidMethod", - String.class, "foobar"); - assertNull(voidResult); - } -} diff --git a/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/UtilityClassCheckerTest.java b/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/UtilityClassCheckerTest.java deleted file mode 100644 index 8c2c5532..00000000 --- a/framework/src/onos/utils/junit/src/test/java/org/onlab/junit/UtilityClassCheckerTest.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.junit; - -import org.junit.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.onlab.junit.UtilityClassChecker.assertThatClassIsUtility; - -/** - * Set of unit tests to check the implementation of the utility class - * checker. - */ -public class UtilityClassCheckerTest { - - // CHECKSTYLE:OFF test data intentionally not final - /** - * Test class for non final class check. - */ - static class NonFinal { - private NonFinal() { } - } - // CHECKSTYLE:ON - - /** - * Check that a non final class correctly produces an error. - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testNonFinalClass() throws Exception { - boolean gotException = false; - try { - assertThatClassIsUtility(NonFinal.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("is not final")); - gotException = true; - } - assertThat(gotException, is(true)); - } - - /** - * Test class for final no constructor class check. - */ - static final class FinalNoConstructor { - } - - /** - * Check that a final class with no declared constructor correctly produces - * an error. In this case, the compiler generates a default constructor - * for you, but the constructor is 'protected' and will fail the check. - * - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testFinalNoConstructorClass() throws Exception { - boolean gotException = false; - try { - assertThatClassIsUtility(FinalNoConstructor.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("class with a default constructor that " + - "is not private")); - gotException = true; - } - assertThat(gotException, is(true)); - } - - /** - * Test class for class with more than one constructor check. - */ - static final class TwoConstructors { - private TwoConstructors() { } - private TwoConstructors(int x) { } - } - - /** - * Check that a non static class correctly produces an error. - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testOnlyOneConstructor() throws Exception { - boolean gotException = false; - try { - assertThatClassIsUtility(TwoConstructors.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("more than one constructor")); - gotException = true; - } - assertThat(gotException, is(true)); - } - - /** - * Test class with a non private constructor. - */ - static final class NonPrivateConstructor { - protected NonPrivateConstructor() { } - } - - /** - * Check that a class with a non private constructor correctly - * produces an error. - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testNonPrivateConstructor() throws Exception { - - boolean gotException = false; - try { - assertThatClassIsUtility(NonPrivateConstructor.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("constructor that is not private")); - gotException = true; - } - assertThat(gotException, is(true)); - } - - /** - * Test class with a non static method. - */ - static final class NonStaticMethod { - private NonStaticMethod() { } - public void aPublicMethod() { } - } - - /** - * Check that a class with a non static method correctly produces an error. - * @throws Exception if any of the reflection lookups fail. - */ - @Test - public void testNonStaticMethod() throws Exception { - - boolean gotException = false; - try { - assertThatClassIsUtility(NonStaticMethod.class); - } catch (AssertionError assertion) { - assertThat(assertion.getMessage(), - containsString("one or more non-static methods")); - gotException = true; - } - assertThat(gotException, is(true)); - } -} diff --git a/framework/src/onos/utils/misc/pom.xml b/framework/src/onos/utils/misc/pom.xml deleted file mode 100644 index 39171e95..00000000 --- a/framework/src/onos/utils/misc/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-misc</artifactId> - <packaging>bundle</packaging> - - <description>Miscellaneous ON.Lab utilities</description> - - <dependencies> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava-testlib</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.easymock</groupId> - <artifactId>easymock</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty</artifactId> - </dependency> - <dependency> - <groupId>commons-lang</groupId> - <artifactId>commons-lang</artifactId> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - </dependency> - - <!-- TODO: do we still need this here? --> - <dependency> - <groupId>com.eclipsesource.minimal-json</groupId> - <artifactId>minimal-json</artifactId> - </dependency> - <dependency> - <groupId>com.esotericsoftware</groupId> - <artifactId>kryo</artifactId> - </dependency> - <dependency> - <groupId>io.dropwizard.metrics</groupId> - <artifactId>metrics-core</artifactId> - <version>3.1.0</version> - </dependency> - <dependency> - <groupId>io.dropwizard.metrics</groupId> - <artifactId>metrics-json</artifactId> - <version>3.1.0</version> - </dependency> - <dependency> - <groupId>org.apache.felix</groupId> - <artifactId>org.apache.felix.scr.annotations</artifactId> - </dependency> - </dependencies> - -</project> diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AbstractEdge.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AbstractEdge.java deleted file mode 100644 index 3e8960e6..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AbstractEdge.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Abstract graph edge implementation. - */ -public abstract class AbstractEdge<V extends Vertex> implements Edge<V> { - - private final V src; - private final V dst; - - /** - * Creates a new edge between the specified source and destination vertexes. - * - * @param src source vertex - * @param dst destination vertex - */ - public AbstractEdge(V src, V dst) { - this.src = checkNotNull(src, "Source vertex cannot be null"); - this.dst = checkNotNull(dst, "Destination vertex cannot be null"); - } - - @Override - public V src() { - return src; - } - - @Override - public V dst() { - return dst; - } - - @Override - public int hashCode() { - return Objects.hash(src, dst); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof AbstractEdge) { - final AbstractEdge other = (AbstractEdge) obj; - return Objects.equals(this.src, other.src) && Objects.equals(this.dst, other.dst); - } - return false; - } - - @Override - public String toString() { - return toStringHelper(this) - .add("src", src) - .add("dst", dst) - .toString(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AbstractGraphPathSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AbstractGraphPathSearch.java deleted file mode 100644 index e7e2c40d..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AbstractGraphPathSearch.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Basis for various graph path search algorithm implementations. - * - * @param <V> vertex type - * @param <E> edge type - */ -public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V>> - implements GraphPathSearch<V, E> { - - private double samenessThreshold = Double.MIN_VALUE; - - /** - * Sets a new sameness threshold for comparing cost values; default is - * is {@link Double#MIN_VALUE}. - * - * @param threshold fractional double value - */ - public void setSamenessThreshold(double threshold) { - samenessThreshold = threshold; - } - - /** - * Returns the current sameness threshold for comparing cost values. - * - * @return current threshold - */ - public double samenessThreshold() { - return samenessThreshold; - } - - /** - * Default path search result that uses the DefaultPath to convey paths - * in a graph. - */ - protected class DefaultResult implements Result<V, E> { - - private final V src; - private final V dst; - protected final Set<Path<V, E>> paths = new HashSet<>(); - protected final Map<V, Double> costs = new HashMap<>(); - protected final Map<V, Set<E>> parents = new HashMap<>(); - protected final int maxPaths; - - /** - * Creates the result of a single-path search. - * - * @param src path source - * @param dst optional path destination - */ - public DefaultResult(V src, V dst) { - this(src, dst, 1); - } - - /** - * Creates the result of path search. - * - * @param src path source - * @param dst optional path destination - * @param maxPaths optional limit of number of paths; - * {@link GraphPathSearch#ALL_PATHS} if no limit - */ - public DefaultResult(V src, V dst, int maxPaths) { - checkNotNull(src, "Source cannot be null"); - this.src = src; - this.dst = dst; - this.maxPaths = maxPaths; - } - - @Override - public V src() { - return src; - } - - @Override - public V dst() { - return dst; - } - - @Override - public Set<Path<V, E>> paths() { - return paths; - } - - @Override - public Map<V, Double> costs() { - return costs; - } - - @Override - public Map<V, Set<E>> parents() { - return parents; - } - - /** - * Indicates whether or not the given vertex has a cost yet. - * - * @param v vertex to test - * @return true if the vertex has cost already - */ - boolean hasCost(V v) { - return costs.get(v) != null; - } - - /** - * Returns the current cost to reach the specified vertex. - * - * @param v vertex to reach - * @return cost to reach the vertex - */ - double cost(V v) { - Double c = costs.get(v); - return c == null ? Double.MAX_VALUE : c; - } - - /** - * Updates the cost of the vertex using its existing cost plus the - * cost to traverse the specified edge. If the search is in single - * path mode, only one path will be accrued. - * - * @param vertex vertex to update - * @param edge edge through which vertex is reached - * @param cost current cost to reach the vertex from the source - * @param replace true to indicate that any accrued edges are to be - * cleared; false to indicate that the edge should be - * added to the previously accrued edges as they yield - * the same cost - */ - void updateVertex(V vertex, E edge, double cost, boolean replace) { - costs.put(vertex, cost); - if (edge != null) { - Set<E> edges = parents.get(vertex); - if (edges == null) { - edges = new HashSet<>(); - parents.put(vertex, edges); - } - if (replace) { - edges.clear(); - } - if (maxPaths == ALL_PATHS || edges.size() < maxPaths) { - edges.add(edge); - } - } - } - - /** - * Removes the set of parent edges for the specified vertex. - * - * @param v vertex - */ - void removeVertex(V v) { - parents.remove(v); - } - - /** - * If possible, relax the specified edge using the supplied base cost - * and edge-weight function. - * - * @param edge edge to be relaxed - * @param cost base cost to reach the edge destination vertex - * @param ew optional edge weight function - * @param forbidNegatives if true negative values will forbid the link - * @return true if the edge was relaxed; false otherwise - */ - boolean relaxEdge(E edge, double cost, EdgeWeight<V, E> ew, - boolean... forbidNegatives) { - V v = edge.dst(); - double oldCost = cost(v); - double hopCost = ew == null ? 1.0 : ew.weight(edge); - if (hopCost < 0 && forbidNegatives.length == 1 && forbidNegatives[0]) { - return false; - } - - double newCost = cost + hopCost; - boolean relaxed = newCost < oldCost; - boolean same = Math.abs(newCost - oldCost) <= samenessThreshold; - if (same || relaxed) { - updateVertex(v, edge, newCost, !same); - } - return relaxed; - } - - /** - * Builds a set of paths for the specified src/dst vertex pair. - */ - protected void buildPaths() { - Set<V> destinations = new HashSet<>(); - if (dst == null) { - destinations.addAll(costs.keySet()); - } else { - destinations.add(dst); - } - - // Build all paths between the source and all requested destinations. - for (V v : destinations) { - // Ignore the source, if it is among the destinations. - if (!v.equals(src)) { - buildAllPaths(this, src, v, maxPaths); - } - } - } - - } - - /** - * Builds a set of all paths between the source and destination using the - * graph search result by applying breadth-first search through the parent - * edges and vertex costs. - * - * @param result graph search result - * @param src source vertex - * @param dst destination vertex - * @param maxPaths limit on the number of paths built; - * {@link GraphPathSearch#ALL_PATHS} if no limit - */ - private void buildAllPaths(DefaultResult result, V src, V dst, int maxPaths) { - DefaultMutablePath<V, E> basePath = new DefaultMutablePath<>(); - basePath.setCost(result.cost(dst)); - - Set<DefaultMutablePath<V, E>> pendingPaths = new HashSet<>(); - pendingPaths.add(basePath); - - while (!pendingPaths.isEmpty() && - (maxPaths == ALL_PATHS || result.paths.size() < maxPaths)) { - Set<DefaultMutablePath<V, E>> frontier = new HashSet<>(); - - for (DefaultMutablePath<V, E> path : pendingPaths) { - // For each pending path, locate its first vertex since we - // will be moving backwards from it. - V firstVertex = firstVertex(path, dst); - - // If the first vertex is our expected source, we have reached - // the beginning, so add the this path to the result paths. - if (firstVertex.equals(src)) { - path.setCost(result.cost(dst)); - result.paths.add(new DefaultPath<>(path.edges(), path.cost())); - - } else { - // If we have not reached the beginning, i.e. the source, - // fetch the set of edges leading to the first vertex of - // this pending path; if there are none, abandon processing - // this path for good. - Set<E> firstVertexParents = result.parents.get(firstVertex); - if (firstVertexParents == null || firstVertexParents.isEmpty()) { - break; - } - - // Now iterate over all the edges and for each of them - // cloning the current path and then insert that edge to - // the path and then add that path to the pending ones. - // When processing the last edge, modify the current - // pending path rather than cloning a new one. - Iterator<E> edges = firstVertexParents.iterator(); - while (edges.hasNext()) { - E edge = edges.next(); - boolean isLast = !edges.hasNext(); - DefaultMutablePath<V, E> pendingPath = isLast ? path : new DefaultMutablePath<>(path); - pendingPath.insertEdge(edge); - frontier.add(pendingPath); - } - } - } - - // All pending paths have been scanned so promote the next frontier - pendingPaths = frontier; - } - } - - // Returns the first vertex of the specified path. This is either the source - // of the first edge or, if there are no edges yet, the given destination. - private V firstVertex(Path<V, E> path, V dst) { - return path.edges().isEmpty() ? dst : path.edges().get(0).src(); - } - - /** - * Checks the specified path search arguments for validity. - * - * @param graph graph; must not be null - * @param src source vertex; must not be null and belong to graph - * @param dst optional target vertex; must belong to graph - */ - protected void checkArguments(Graph<V, E> graph, V src, V dst) { - checkNotNull(graph, "Graph cannot be null"); - checkNotNull(src, "Source cannot be null"); - Set<V> vertices = graph.getVertexes(); - checkArgument(vertices.contains(src), "Source not in the graph"); - checkArgument(dst == null || vertices.contains(dst), - "Destination not in graph"); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AdjacencyListsGraph.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AdjacencyListsGraph.java deleted file mode 100644 index 3890dcf8..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/AdjacencyListsGraph.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSetMultimap; - -import java.util.Objects; -import java.util.Set; - -import static com.google.common.base.MoreObjects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Immutable graph implemented using adjacency lists. - * - * @param <V> vertex type - * @param <E> edge type - */ -public class AdjacencyListsGraph<V extends Vertex, E extends Edge<V>> - implements Graph<V, E> { - - private final Set<V> vertexes; - private final Set<E> edges; - - private final ImmutableSetMultimap<V, E> sources; - private final ImmutableSetMultimap<V, E> destinations; - - /** - * Creates a graph comprising of the specified vertexes and edges. - * - * @param vertexes set of graph vertexes - * @param edges set of graph edges - */ - public AdjacencyListsGraph(Set<V> vertexes, Set<E> edges) { - checkNotNull(vertexes, "Vertex set cannot be null"); - checkNotNull(edges, "Edge set cannot be null"); - - // Record ingress/egress edges for each vertex. - ImmutableSetMultimap.Builder<V, E> srcMap = ImmutableSetMultimap.builder(); - ImmutableSetMultimap.Builder<V, E> dstMap = ImmutableSetMultimap.builder(); - - // Also make sure that all edge end-points are added as vertexes - ImmutableSet.Builder<V> actualVertexes = ImmutableSet.builder(); - actualVertexes.addAll(vertexes); - - for (E edge : edges) { - srcMap.put(edge.src(), edge); - actualVertexes.add(edge.src()); - dstMap.put(edge.dst(), edge); - actualVertexes.add(edge.dst()); - } - - // Make an immutable copy of the edge and vertex sets - this.edges = ImmutableSet.copyOf(edges); - this.vertexes = actualVertexes.build(); - - // Build immutable copies of sources and destinations edge maps - sources = srcMap.build(); - destinations = dstMap.build(); - } - - @Override - public Set<V> getVertexes() { - return vertexes; - } - - @Override - public Set<E> getEdges() { - return edges; - } - - @Override - public Set<E> getEdgesFrom(V src) { - return sources.get(src); - } - - @Override - public Set<E> getEdgesTo(V dst) { - return destinations.get(dst); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof AdjacencyListsGraph) { - AdjacencyListsGraph that = (AdjacencyListsGraph) obj; - return this.getClass() == that.getClass() && - Objects.equals(this.vertexes, that.vertexes) && - Objects.equals(this.edges, that.edges); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(vertexes, edges); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("vertexes", vertexes) - .add("edges", edges) - .toString(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/BellmanFordGraphSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/BellmanFordGraphSearch.java deleted file mode 100644 index dc741f73..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/BellmanFordGraphSearch.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -/** - * Bellman-Ford graph search algorithm for locating shortest-paths in - * directed graphs that may contain negative cycles. - */ -public class BellmanFordGraphSearch<V extends Vertex, E extends Edge<V>> - extends AbstractGraphPathSearch<V, E> { - - @Override - public Result<V, E> search(Graph<V, E> graph, V src, V dst, - EdgeWeight<V, E> weight, int maxPaths) { - checkArguments(graph, src, dst); - - // Prepare the graph search result. - DefaultResult result = new DefaultResult(src, dst, maxPaths); - - // The source vertex has cost 0, of course. - result.updateVertex(src, null, 0.0, true); - - int max = graph.getVertexes().size() - 1; - for (int i = 0; i < max; i++) { - // Relax, if possible, all egress edges of the current vertex. - for (E edge : graph.getEdges()) { - if (result.hasCost(edge.src())) { - result.relaxEdge(edge, result.cost(edge.src()), weight); - } - } - } - - // Remove any vertexes reached by traversing edges with negative weights. - for (E edge : graph.getEdges()) { - if (result.hasCost(edge.src())) { - if (result.relaxEdge(edge, result.cost(edge.src()), weight)) { - result.removeVertex(edge.dst()); - } - } - } - - // Finally, but the paths on the search result and return. - result.buildPaths(); - return result; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java deleted file mode 100644 index 40c8735b..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/BreadthFirstSearch.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.HashSet; -import java.util.Set; - -/** - * Implementation of the BFS algorithm. - */ -public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>> - extends AbstractGraphPathSearch<V, E> { - - @Override - public Result<V, E> search(Graph<V, E> graph, V src, V dst, - EdgeWeight<V, E> weight, int maxPaths) { - checkArguments(graph, src, dst); - - // Prepare the graph result. - DefaultResult result = new DefaultResult(src, dst, maxPaths); - - // Setup the starting frontier with the source as the sole vertex. - Set<V> frontier = new HashSet<>(); - result.updateVertex(src, null, 0.0, true); - frontier.add(src); - - boolean reachedEnd = false; - while (!reachedEnd && !frontier.isEmpty()) { - // Prepare the next frontier. - Set<V> next = new HashSet<>(); - - // Visit all vertexes in the current frontier. - for (V vertex : frontier) { - double cost = result.cost(vertex); - - // Visit all egress edges of the current frontier vertex. - for (E edge : graph.getEdgesFrom(vertex)) { - V nextVertex = edge.dst(); - if (!result.hasCost(nextVertex)) { - // If this vertex has not been visited yet, update it. - double newCost = cost + (weight == null ? 1.0 : weight.weight(edge)); - result.updateVertex(nextVertex, edge, newCost, true); - // If we have reached our intended destination, bail. - if (nextVertex.equals(dst)) { - reachedEnd = true; - break; - } - next.add(nextVertex); - } - - if (reachedEnd) { - break; - } - } - } - - // Promote the next frontier. - frontier = next; - } - - // Finally, but the paths on the search result and return. - result.buildPaths(); - return result; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DefaultMutablePath.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DefaultMutablePath.java deleted file mode 100644 index ad7e8402..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DefaultMutablePath.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.collect.ImmutableList; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Simple concrete implementation of a directed graph path. - */ -public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements MutablePath<V, E> { - - private final List<E> edges = new ArrayList<>(); - private double cost = 0.0; - - /** - * Creates a new empty path. - */ - public DefaultMutablePath() { - } - - /** - * Creates a new path as a copy of another path. - * - * @param path path to be copied - */ - public DefaultMutablePath(Path<V, E> path) { - checkNotNull(path, "Path cannot be null"); - this.cost = path.cost(); - edges.addAll(path.edges()); - } - - @Override - public V src() { - return edges.isEmpty() ? null : edges.get(0).src(); - } - - @Override - public V dst() { - return edges.isEmpty() ? null : edges.get(edges.size() - 1).dst(); - } - - @Override - public double cost() { - return cost; - } - - @Override - public List<E> edges() { - return ImmutableList.copyOf(edges); - } - - @Override - public void setCost(double cost) { - this.cost = cost; - } - - @Override - public Path<V, E> toImmutable() { - return new DefaultPath<>(edges, cost); - } - - @Override - public void insertEdge(E edge) { - checkNotNull(edge, "Edge cannot be null"); - checkArgument(edges.isEmpty() || src().equals(edge.dst()), - "Edge destination must be the same as the current path source"); - edges.add(0, edge); - } - - @Override - public void appendEdge(E edge) { - checkNotNull(edge, "Edge cannot be null"); - checkArgument(edges.isEmpty() || dst().equals(edge.src()), - "Edge source must be the same as the current path destination"); - edges.add(edge); - } - - @Override - public void removeEdge(E edge) { - checkArgument(edge.src().equals(edge.dst()) || - edges.indexOf(edge) == 0 || - edges.lastIndexOf(edge) == edges.size() - 1, - "Edge must be at start or end of path, or it must be a cyclic edge"); - edges.remove(edge); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("src", src()) - .add("dst", dst()) - .add("cost", cost) - .add("edges", edges) - .toString(); - } - - @Override - public int hashCode() { - return Objects.hash(edges, cost); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof DefaultMutablePath) { - final DefaultMutablePath other = (DefaultMutablePath) obj; - return Objects.equals(this.cost, other.cost) && - Objects.equals(this.edges, other.edges); - } - return false; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DefaultPath.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DefaultPath.java deleted file mode 100644 index 816fb161..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DefaultPath.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.collect.ImmutableList; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Simple concrete implementation of a directed graph path. - */ -public class DefaultPath<V extends Vertex, E extends Edge<V>> implements Path<V, E> { - - private final V src; - private final V dst; - private final List<E> edges; - private double cost = 0.0; - - /** - * Creates a new path from the specified list of edges and cost. - * - * @param edges list of path edges - * @param cost path cost as a unit-less number - */ - public DefaultPath(List<E> edges, double cost) { - checkNotNull(edges, "Edges list must not be null"); - checkArgument(!edges.isEmpty(), "There must be at least one edge"); - this.edges = ImmutableList.copyOf(edges); - this.src = edges.get(0).src(); - this.dst = edges.get(edges.size() - 1).dst(); - this.cost = cost; - } - - @Override - public V src() { - return src; - } - - @Override - public V dst() { - return dst; - } - - @Override - public double cost() { - return cost; - } - - @Override - public List<E> edges() { - return Collections.unmodifiableList(edges); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("src", src) - .add("dst", dst) - .add("cost", cost) - .add("edges", edges) - .toString(); - } - - @Override - public int hashCode() { - return Objects.hash(src, dst, edges, cost); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof DefaultPath) { - final DefaultPath other = (DefaultPath) obj; - return Objects.equals(this.src, other.src) && - Objects.equals(this.dst, other.dst) && - Objects.equals(this.cost, other.cost) && - Objects.equals(this.edges, other.edges); - } - return false; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DepthFirstSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DepthFirstSearch.java deleted file mode 100644 index 91b5108f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DepthFirstSearch.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Stack; - -/** - * DFS graph search algorithm implemented via iteration rather than recursion. - */ -public class DepthFirstSearch<V extends Vertex, E extends Edge<V>> - extends AbstractGraphPathSearch<V, E> { - - /** - * Graph edge types as classified by the DFS algorithm. - */ - public static enum EdgeType { - TREE_EDGE, FORWARD_EDGE, BACK_EDGE, CROSS_EDGE - } - - @Override - public SpanningTreeResult search(Graph<V, E> graph, V src, V dst, - EdgeWeight<V, E> weight, int maxPaths) { - checkArguments(graph, src, dst); - - // Prepare the search result. - SpanningTreeResult result = new SpanningTreeResult(src, dst, maxPaths); - - // The source vertex has cost 0, of course. - result.updateVertex(src, null, 0.0, true); - - // Track finished vertexes and keep a stack of vertexes that have been - // started; start this stack with the source on it. - Set<V> finished = new HashSet<>(); - Stack<V> stack = new Stack<>(); - stack.push(src); - - while (!stack.isEmpty()) { - V vertex = stack.peek(); - if (vertex.equals(dst)) { - // If we have reached our destination, bail. - break; - } - - double cost = result.cost(vertex); - boolean tangent = false; - - // Visit all egress edges of the current vertex. - for (E edge : graph.getEdgesFrom(vertex)) { - // If we have seen the edge already, skip it. - if (result.isEdgeMarked(edge)) { - continue; - } - - // Examine the destination of the current edge. - V nextVertex = edge.dst(); - if (!result.hasCost(nextVertex)) { - // If this vertex have not finished this vertex yet, - // not started it, then start it as a tree-edge. - result.markEdge(edge, EdgeType.TREE_EDGE); - double newCost = cost + (weight == null ? 1.0 : weight.weight(edge)); - result.updateVertex(nextVertex, edge, newCost, true); - stack.push(nextVertex); - tangent = true; - break; - - } else if (!finished.contains(nextVertex)) { - // We started the vertex, but did not yet finish it, so - // it must be a back-edge. - result.markEdge(edge, EdgeType.BACK_EDGE); - } else { - // The target has been finished already, so what we have - // here is either a forward-edge or a cross-edge. - result.markEdge(edge, isForwardEdge(result, edge) ? - EdgeType.FORWARD_EDGE : EdgeType.CROSS_EDGE); - } - } - - // If we have not been sent on a tangent search and reached the - // end of the current scan normally, mark the node as finished - // and pop it off the vertex stack. - if (!tangent) { - finished.add(vertex); - stack.pop(); - } - } - - // Finally, but the paths on the search result and return. - result.buildPaths(); - return result; - } - - /** - * Determines whether the specified edge is a forward edge using the - * accumulated set of parent edges for each vertex. - * - * @param result search result - * @param edge edge to be classified - * @return true if the edge is a forward edge - */ - protected boolean isForwardEdge(DefaultResult result, E edge) { - // Follow the parent edges until we hit the edge source vertex - V target = edge.src(); - V vertex = edge.dst(); - Set<E> parentEdges; - while ((parentEdges = result.parents.get(vertex)) != null) { - for (E parentEdge : parentEdges) { - vertex = parentEdge.src(); - if (vertex.equals(target)) { - return true; - } - } - } - return false; - } - - /** - * Graph search result which includes edge classification for building - * a spanning tree. - */ - public class SpanningTreeResult extends DefaultResult { - - protected final Map<E, EdgeType> edges = new HashMap<>(); - - /** - * Creates a new spanning tree result. - * - * @param src search source - * @param dst optional search destination - * @param maxPaths limit on the number of paths - */ - public SpanningTreeResult(V src, V dst, int maxPaths) { - super(src, dst, maxPaths); - } - - /** - * Returns the map of edge type. - * - * @return edge to edge type bindings - */ - public Map<E, EdgeType> edges() { - return edges; - } - - /** - * Indicates whether or not the edge has been marked with type. - * - * @param edge edge to test - * @return true if the edge has been marked already - */ - boolean isEdgeMarked(E edge) { - return edges.containsKey(edge); - } - - /** - * Marks the edge with the specified type. - * - * @param edge edge to mark - * @param type edge type - */ - void markEdge(E edge, EdgeType type) { - edges.put(edge, type); - } - - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java deleted file mode 100644 index b1892ee1..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DijkstraGraphSearch.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Set; - -/** - * Dijkstra shortest-path graph search algorithm capable of finding not just - * one, but all shortest paths between the source and destinations. - */ -public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>> - extends AbstractGraphPathSearch<V, E> { - - @Override - public Result<V, E> search(Graph<V, E> graph, V src, V dst, - EdgeWeight<V, E> weight, int maxPaths) { - checkArguments(graph, src, dst); - - // Use the default result to remember cumulative costs and parent - // edges to each each respective vertex. - DefaultResult result = new DefaultResult(src, dst, maxPaths); - - // Cost to reach the source vertex is 0 of course. - result.updateVertex(src, null, 0.0, false); - - if (graph.getEdges().isEmpty()) { - result.buildPaths(); - return result; - } - - // Use the min priority queue to progressively find each nearest - // vertex until we reach the desired destination, if one was given, - // or until we reach all possible destinations. - Heap<V> minQueue = createMinQueue(graph.getVertexes(), - new PathCostComparator(result)); - while (!minQueue.isEmpty()) { - // Get the nearest vertex - V nearest = minQueue.extractExtreme(); - if (nearest.equals(dst)) { - break; - } - - // Find its cost and use it to determine if the vertex is reachable. - double cost = result.cost(nearest); - if (cost < Double.MAX_VALUE) { - // If the vertex is reachable, relax all its egress edges. - for (E e : graph.getEdgesFrom(nearest)) { - result.relaxEdge(e, cost, weight, true); - } - } - - // Re-prioritize the min queue. - minQueue.heapify(); - } - - // Now construct a set of paths from the results. - result.buildPaths(); - return result; - } - - // Compares path weights using their accrued costs; used for sorting the - // min priority queue. - private final class PathCostComparator implements Comparator<V> { - private final DefaultResult result; - - private PathCostComparator(DefaultResult result) { - this.result = result; - } - - @Override - public int compare(V v1, V v2) { - double delta = result.cost(v2) - result.cost(v1); - return delta < 0 ? -1 : (delta > 0 ? 1 : 0); - } - } - - // Creates a min priority queue from the specified vertexes and comparator. - private Heap<V> createMinQueue(Set<V> vertexes, Comparator<V> comparator) { - return new Heap<>(new ArrayList<>(vertexes), comparator); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DisjointPathPair.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DisjointPathPair.java deleted file mode 100644 index dfa150e3..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/DisjointPathPair.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.List; -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Pair of disjoint paths. - * - * @param <V> type of vertex - * @param <E> type of edge - */ -public class DisjointPathPair<V extends Vertex, E extends Edge<V>> implements Path<V, E> { - - private final Path<V, E> primary, secondary; - private boolean primaryActive = true; - - /** - * Creates a disjoint path pair from two paths. - * - * @param primary primary path - * @param secondary secondary path - */ - public DisjointPathPair(Path<V, E> primary, Path<V, E> secondary) { - this.primary = primary; - this.secondary = secondary; - } - - @Override - public V src() { - return primary.src(); - } - - @Override - public V dst() { - return primary.dst(); - } - - /** - * Returns the primary path. - * - * @return primary path - */ - public Path<V, E> primary() { - return primary; - } - - /** - * Returns the secondary path. - * - * @return primary path - */ - public Path<V, E> secondary() { - return secondary; - } - - @Override - public double cost() { - return hasBackup() ? primary.cost() + secondary.cost() : primary.cost(); - } - - @Override - public List<E> edges() { - return primaryActive || !hasBackup() ? primary.edges() : secondary.edges(); - } - - /** - * Checks if this path pair contains a backup/secondary path. - * - * @return boolean representing whether it has backup - */ - public boolean hasBackup() { - return secondary != null; - } - - @Override - public String toString() { - return toStringHelper(this) - .add("src", src()) - .add("dst", dst()) - .add("cost", cost()) - .add("edges", edges()) - .toString(); - } - - @Override - public int hashCode() { - // Note: DisjointPathPair with primary and secondary swapped - // must result in same hashCode - return hasBackup() ? primary.hashCode() + secondary.hashCode() : - Objects.hash(primary); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof DisjointPathPair) { - final DisjointPathPair other = (DisjointPathPair) obj; - return Objects.equals(this.src(), other.src()) && - Objects.equals(this.dst(), other.dst()) && - (Objects.equals(this.primary, other.primary) && - Objects.equals(this.secondary, other.secondary)) || - (Objects.equals(this.primary, other.secondary) && - Objects.equals(this.secondary, other.primary)); - } - return false; - } - - /** - * Returns number of paths inside this path pair object. - * - * @return number of paths - */ - public int size() { - return hasBackup() ? 2 : 1; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Edge.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Edge.java deleted file mode 100644 index 1bbfbf99..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Edge.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -/** - * Representation of a graph edge. - * - * @param <V> vertex type - */ -public interface Edge<V extends Vertex> { - - /** - * Returns the edge source vertex. - * - * @return source vertex - */ - V src(); - - /** - * Returns the edge destination vertex. - * - * @return destination vertex - */ - V dst(); - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/EdgeWeight.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/EdgeWeight.java deleted file mode 100644 index 975b59c7..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/EdgeWeight.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -/** - * Abstraction of a graph edge weight function. - */ -public interface EdgeWeight<V extends Vertex, E extends Edge<V>> { - - /** - * Returns the weight of the given edge as a unit-less number. - * - * @param edge edge to be weighed - * @return edge weight as a unit-less number - */ - double weight(E edge); - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GAOrganism.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GAOrganism.java deleted file mode 100644 index a0e0570d..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GAOrganism.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.graph; - -/** - * Interface representing an "organism": a specific solution - * to a problem where solutions can be evaluated in terms - * of fitness. These organisms can be used to represent any - * class of problem that genetic algorithms can be run on. - */ -interface GAOrganism { - /** - * A fitness function that determines how - * optimal a given organism is. - * - * @return fitness of organism - */ - double fitness(); - - /** - * A method that slightly mutates an organism. - */ - void mutate(); - - /** - * Creates a new random organism. - * - * @return random GAOrganism - */ - GAOrganism random(); - - /** - * Returns a child organism that is the result - * of "crossing" this organism with another. - * - * @param other Other organism to cross with - * @return child organism - */ - GAOrganism crossWith(GAOrganism other); -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GAPopulation.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GAPopulation.java deleted file mode 100644 index c5fa9b45..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GAPopulation.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -/** - * Represents a population of GAOrganisms. This class can be used - * to run a genetic algorithm on the population and return the fittest solutions. - */ -class GAPopulation<Organism extends GAOrganism> extends ArrayList<Organism> { - Random r = new Random(); - - /** - * Steps the population through one generation. The 75% least fit - * organisms are killed off and replaced with the children of the - * 25% (as well as some "random" newcomers). - */ - void step() { - Collections.sort(this, (org1, org2) -> { - double d = org1.fitness() - org2.fitness(); - if (d < 0) { - return -1; - } else if (d == 0) { - return 0; - } - return 1; - }); - int maxSize = size(); - for (int i = size() - 1; i > maxSize / 4; i--) { - remove(i); - } - for (Organism org: this) { - if (r.nextBoolean()) { - org.mutate(); - } - } - while (size() < maxSize * 4 / 5) { - Organism org1 = get(r.nextInt(size())); - Organism org2 = get(r.nextInt(size())); - add((Organism) org1.crossWith(org2)); - } - - while (size() < maxSize) { - Organism org1 = get(r.nextInt(size())); - add((Organism) org1.random()); - } - } - - /** - * Runs GA for the specified number of iterations, and returns - * a sample of the resulting population of solutions. - * - * @param generations Number of generations to run GA for - * @param populationSize Population size of GA - * @param sample Number of solutions to ask for - * @param template Template GAOrganism to seed the population with - * @return ArrayList containing sample number of organisms - */ - List<Organism> runGA(int generations, int populationSize, int sample, Organism template) { - for (int i = 0; i < populationSize; i++) { - add((Organism) template.random()); - } - - for (int i = 0; i < generations; i++) { - step(); - } - for (int i = size() - 1; i >= sample; i--) { - remove(i); - } - return new ArrayList<>(this); - } -} - diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Graph.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Graph.java deleted file mode 100644 index bc7853ec..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Graph.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - - -import java.util.Set; - -/** - * Abstraction of a directed graph structure. - * - * @param <V> vertex type - * @param <E> edge type - */ -public interface Graph<V extends Vertex, E extends Edge> { - - /** - * Returns the set of vertexes comprising the graph. - * - * @return set of vertexes - */ - Set<V> getVertexes(); - - /** - * Returns the set of edges comprising the graph. - * - * @return set of edges - */ - Set<E> getEdges(); - - /** - * Returns all edges leading out from the specified source vertex. - * - * @param src source vertex - * @return set of egress edges; empty if no such edges - */ - Set<E> getEdgesFrom(V src); - - /** - * Returns all edges leading towards the specified destination vertex. - * - * @param dst destination vertex - * @return set of ingress vertexes; empty if no such edges - */ - Set<E> getEdgesTo(V dst); - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GraphPathSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GraphPathSearch.java deleted file mode 100644 index caebce47..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GraphPathSearch.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.Map; -import java.util.Set; - -/** - * Representation of a graph path search algorithm. - * - * @param <V> vertex type - * @param <E> edge type - */ -public interface GraphPathSearch<V extends Vertex, E extends Edge<V>> { - - static int ALL_PATHS = -1; - - /** - * Abstraction of a path search result. - */ - interface Result<V extends Vertex, E extends Edge<V>> { - - /** - * Returns the search source. - * - * @return search source - */ - V src(); - - /** - * Returns the search destination, if was was given. - * - * @return optional search destination - */ - V dst(); - - /** - * Returns the set of paths produced as a result of the graph search. - * - * @return set of paths - */ - Set<Path<V, E>> paths(); - - /** - * Returns bindings of each vertex to its parent edges in the path. - * - * @return map of vertex to its parent edge bindings - */ - Map<V, Set<E>> parents(); - - /** - * Return a bindings of each vertex to its cost in the path. - * - * @return map of vertex to path cost bindings - */ - Map<V, Double> costs(); - } - - /** - * Searches the specified graph for paths between vertices. - * - * @param graph graph to be searched - * @param src optional source vertex - * @param dst optional destination vertex; if null paths to all vertex - * destinations will be searched - * @param weight optional edge-weight; if null cost of each edge will be - * assumed to be 1.0 - * @param maxPaths limit on number of paths; {@link GraphPathSearch#ALL_PATHS} if no limit - * @return search results - */ - Result<V, E> search(Graph<V, E> graph, V src, V dst, - EdgeWeight<V, E> weight, int maxPaths); - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GraphSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GraphSearch.java deleted file mode 100644 index ca369a7d..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/GraphSearch.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -/** - * Representation of a graph search algorithm and its outcome. - * - * @param <V> vertex type - * @param <E> edge type - */ -public interface GraphSearch<V extends Vertex, E extends Edge<V>> { - - /** - * Notion of a graph search result. - */ - interface Result<V extends Vertex, E extends Edge<V>> { - } - - /** - * Searches the specified graph. - * - * @param graph graph to be searched - * @param weight optional edge-weight; if null cost of each edge will be - * assumed to be 1.0 - * - * @return search results - */ - Result search(Graph<V, E> graph, EdgeWeight<V, E> weight); - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Heap.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Heap.java deleted file mode 100644 index ebb1a60b..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Heap.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.collect.ImmutableList; - -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Implementation of an array-backed heap structure whose sense of order is - * imposed by the provided comparator. - * <p> - * While this provides similar functionality to {@link java.util.PriorityQueue} - * data structure, one key difference is that external entities can control - * when to restore the heap property, which is done through invocation of the - * {@link #heapify} method. - * </p> - * <p> - * This class is not thread-safe and care must be taken to prevent concurrent - * modifications. - * </p> - * - * @param <T> type of the items on the heap - */ -public class Heap<T> { - - private final List<T> data; - private final Comparator<T> comparator; - - /** - * Creates a new heap backed by the specified list. In the interest of - * efficiency, the list should be array-backed. Also, for the same reason, - * the data is not copied and therefore, the caller must assure that the - * backing data is not altered in any way. - * - * @param data backing data list - * @param comparator comparator for ordering the heap items - */ - public Heap(List<T> data, Comparator<T> comparator) { - this.data = checkNotNull(data, "Data cannot be null"); - this.comparator = checkNotNull(comparator, "Comparator cannot be null"); - heapify(); - } - - /** - * Restores the heap property by re-arranging the elements in the backing - * array as necessary following any heap modifications. - */ - public void heapify() { - for (int i = data.size() / 2; i >= 0; i--) { - heapify(i); - } - } - - /** - * Returns the current size of the heap. - * - * @return number of items in the heap - */ - public int size() { - return data.size(); - } - - /** - * Returns true if there are no items in the heap. - * - * @return true if heap is empty - */ - public boolean isEmpty() { - return data.isEmpty(); - } - - /** - * Returns the most extreme item in the heap. - * - * @return heap extreme or null if the heap is empty - */ - public T extreme() { - return data.isEmpty() ? null : data.get(0); - } - - /** - * Extracts and returns the most extreme item from the heap. - * - * @return heap extreme or null if the heap is empty - */ - public T extractExtreme() { - if (!isEmpty()) { - T extreme = extreme(); - - data.set(0, data.get(data.size() - 1)); - data.remove(data.size() - 1); - heapify(); - return extreme; - } - return null; - } - - /** - * Inserts the specified item into the heap and returns the modified heap. - * - * @param item item to be inserted - * @return the heap self - * @throws IllegalArgumentException if the heap is already full - */ - public Heap<T> insert(T item) { - data.add(item); - bubbleUp(); - return this; - } - - /** - * Returns iterator to traverse the heap level-by-level. This iterator - * does not permit removal of items. - * - * @return non-destructive heap iterator - */ - public Iterator<T> iterator() { - return ImmutableList.copyOf(data).iterator(); - } - - // Bubbles up the last item in the heap to its proper position to restore - // the heap property. - private void bubbleUp() { - int child = data.size() - 1; - while (child > 0) { - int parent = child / 2; - if (comparator.compare(data.get(child), data.get(parent)) < 0) { - break; - } - swap(child, parent); - child = parent; - } - } - - // Restores the heap property of the specified heap layer. - private void heapify(int i) { - int left = 2 * i + 1; - int right = 2 * i; - int extreme = i; - - if (left < data.size() && - comparator.compare(data.get(extreme), data.get(left)) < 0) { - extreme = left; - } - - if (right < data.size() && - comparator.compare(data.get(extreme), data.get(right)) < 0) { - extreme = right; - } - - if (extreme != i) { - swap(i, extreme); - heapify(extreme); - } - } - - // Swaps two heap items identified by their respective indexes. - private void swap(int i, int k) { - T aux = data.get(i); - data.set(i, data.get(k)); - data.set(k, aux); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof Heap) { - Heap that = (Heap) obj; - return this.getClass() == that.getClass() && - Objects.equals(this.comparator, that.comparator) && - Objects.deepEquals(this.data, that.data); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(comparator, data); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("data", data) - .add("comparator", comparator) - .toString(); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/KshortestPathSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/KshortestPathSearch.java deleted file mode 100644 index 820e912c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/KshortestPathSearch.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.ArrayList; -//import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -//import java.util.Map; -//import java.util.PriorityQueue; -import java.util.Set; - -import static org.onlab.graph.GraphPathSearch.ALL_PATHS; - -/** - * K-shortest-path graph search algorithm capable of finding not just one, - * but K shortest paths with ascending order between the source and destinations. - */ - -public class KshortestPathSearch<V extends Vertex, E extends Edge<V>> { - - // Define class variables. - private Graph<V, E> immutableGraph; - private MutableGraph<V, E> mutableGraph; - private List<List<E>> pathResults = new ArrayList<List<E>>(); - private List<List<E>> pathCandidates = new ArrayList<List<E>>(); - private V source; - private V sink; - private int numK = 0; - private EdgeWeight<V, E> weight = null; - // private PriorityQueue<List<E>> pathCandidates = new PriorityQueue<List<E>>(); - - // Initialize the graph. - public KshortestPathSearch(Graph<V, E> graph) { - immutableGraph = graph; - mutableGraph = new MutableAdjacencyListsGraph<>(graph.getVertexes(), - graph.getEdges()); - } - - public List<List<E>> search(V src, - V dst, - EdgeWeight<V, E> wei, - int k) { - - weight = wei; - source = src; - sink = dst; - numK = k; - // pathCandidates = new PriorityQueue<List<E>>(); - - pathResults.clear(); - pathCandidates.clear(); - - // Double check the parameters - checkArguments(immutableGraph, src, dst, numK); - - // DefaultResult result = new DefaultResult(src, dst); - - searchKShortestPaths(); - - return pathResults; - } - - private void checkArguments(Graph<V, E> graph, V src, V dst, int k) { - if (graph == null) { - throw new NullPointerException("graph is null"); - } - if (!graph.getVertexes().contains(src)) { - throw new NullPointerException("source node does not exist"); - } - if (!graph.getVertexes().contains(dst)) { - throw new NullPointerException("target node does not exist"); - } - if (k <= 0) { - throw new NullPointerException("K is negative or 0"); - } - if (weight == null) { - throw new NullPointerException("the cost matrix is null"); - } - } - - private void searchKShortestPaths() { - // Step 1: find the shortest path. - List<E> shortestPath = searchShortestPath(immutableGraph, source, sink); - // no path exists, exit. - if (shortestPath == null) { - return; - } - - // Step 2: update the results. - pathResults.add(shortestPath); - // pathCandidates.add(shortestPath); - - // Step 3: find the other K-1 paths. - while (/*pathCandidates.size() > 0 &&*/pathResults.size() < numK) { - // 3.1 the spur node ranges from the first node to the last node in the previous k-shortest path. - List<E> lastPath = pathResults.get(pathResults.size() - 1); - for (int i = 0; i < lastPath.size(); i++) { - // 3.1.1 convert the graph into mutable. - convertGraph(); - // 3.1.2 transform the graph. - List<E> rootPath = createSpurNode(lastPath, i); - transformGraph(rootPath); - // 3.1.3 find the deviation node. - V devNode; - devNode = getDevNode(rootPath); - List<E> spurPath; - // 3.1.4 find the shortest path in the transformed graph. - spurPath = searchShortestPath(mutableGraph, devNode, sink); - // 3.1.5 update the path candidates. - if (spurPath != null) { - // totalPath = rootPath + spurPath; - rootPath.addAll(spurPath); - pathCandidates.add(rootPath); - } - } - // 3.2 if there is no spur path, exit. - if (pathCandidates.size() == 0) { - break; - } - // 3.3 add the path into the results. - addPathResult(); - } - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private List<E> searchShortestPath(Graph<V, E> graph, V src, V dst) { - // Determine the shortest path from the source to the destination by using the Dijkstra algorithm. - DijkstraGraphSearch dijkstraAlg = new DijkstraGraphSearch(); - Set<Path> paths = dijkstraAlg.search(graph, src, dst, weight, ALL_PATHS).paths(); - Iterator<Path> itr = paths.iterator(); - if (!itr.hasNext()) { - return null; - } - // return the first shortest path only. - return (List<E>) itr.next().edges(); - } - - private void convertGraph() { - // clear the mutableGraph first - if (mutableGraph != null) { - ((MutableAdjacencyListsGraph) mutableGraph).clear(); - } - - // create a immutableGraph - Set<E> copyEa = immutableGraph.getEdges(); - Set<V> copyVa = immutableGraph.getVertexes(); - for (V vertex : copyVa) { - mutableGraph.addVertex(vertex); - } - for (E edge : copyEa) { - mutableGraph.addEdge(edge); - } - } - - private V getDevNode(List<E> path) { - V srcA; - V dstB; - - if (path.size() == 0) { - return source; - } - - E temp1 = path.get(path.size() - 1); - srcA = temp1.src(); - dstB = temp1.dst(); - - if (path.size() == 1) { - if (srcA.equals(source)) { - return dstB; - } else { - return srcA; - } - } else { - E temp2 = path.get(path.size() - 2); - if (srcA.equals(temp2.src()) || srcA.equals(temp2.dst())) { - return dstB; - } else { - return srcA; - } - } - } - - private List<E> createSpurNode(List<E> path, int n) { - List<E> root = new ArrayList<E>(); - - for (int i = 0; i < n; i++) { - root.add(path.get(i)); - } - return root; - } - - private void transformGraph(List<E> rootPath) { - List<E> prePath; - //remove edges - for (int i = 0; i < pathResults.size(); i++) { - prePath = pathResults.get(i); - if (prePath.size() == 1) { - mutableGraph.removeEdge(prePath.get(0)); - } else if (comparePath(rootPath, prePath)) { - for (int j = 0; j <= rootPath.size(); j++) { - mutableGraph.removeEdge(prePath.get(j)); - } - } - } - for (int i = 0; i < pathCandidates.size(); i++) { - prePath = pathCandidates.get(i); - if (prePath.size() == 1) { - mutableGraph.removeEdge(prePath.get(0)); - } else if (comparePath(rootPath, prePath)) { - for (int j = 0; j <= rootPath.size(); j++) { - mutableGraph.removeEdge(prePath.get(j)); - } - } - } - - if (rootPath.size() == 0) { - return; - } - - //remove nodes - List<V> nodes = new ArrayList<V>(); - nodes.add(source); - V pre = source; - V srcA; - V dstB; - for (int i = 0; i < rootPath.size() - 1; i++) { - E temp = rootPath.get(i); - srcA = temp.src(); - dstB = temp.dst(); - - if (srcA.equals(pre)) { - nodes.add(dstB); - pre = dstB; - } else { - nodes.add(srcA); - pre = srcA; - } - } - for (int i = 0; i < nodes.size(); i++) { - mutableGraph.removeVertex(nodes.get(i)); - } - } - - private boolean comparePath(List<E> path1, List<E> path2) { - if (path1.size() > path2.size()) { - return false; - } - if (path1.size() == 0) { - return true; - } - for (int i = 0; i < path1.size(); i++) { - if (path1.get(i) != path2.get(i)) { - return false; - } - } - return true; - } - - private void addPathResult() { - List<E> sp; - sp = pathCandidates.get(0); - for (int i = 1; i < pathCandidates.size(); i++) { - if (sp.size() > pathCandidates.get(i).size()) { - sp = pathCandidates.get(i); - } - } - pathResults.add(sp); - // Log.info(sp.toString()); - pathCandidates.remove(sp); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutableAdjacencyListsGraph.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutableAdjacencyListsGraph.java deleted file mode 100644 index 87571c4b..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutableAdjacencyListsGraph.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import static com.google.common.base.MoreObjects.toStringHelper; - -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.SetMultimap; - -public class MutableAdjacencyListsGraph<V extends Vertex, E extends Edge<V>> -implements MutableGraph<V, E> { - private Set<V> vertexes = new HashSet<V>(); - private Set<E> edges = new HashSet<E>(); - - private SetMultimap<V, E> sources = HashMultimap.create(); - private SetMultimap<V, E> destinations = HashMultimap.create(); - - /** - * Creates a graph comprising of the specified vertexes and edges. - * - * @param vertex set of graph vertexes - * @param edge set of graph edges - */ - public MutableAdjacencyListsGraph(Set<V> vertex, Set<E> edge) { - vertexes.addAll(vertex); - edges.addAll(edge); - for (E e : edge) { - sources.put(e.src(), e); - vertexes.add(e.src()); - destinations.put(e.dst(), e); - vertexes.add(e.dst()); - } - } - - @Override - public Set<V> getVertexes() { - return vertexes; - } - - @Override - public Set<E> getEdges() { - return edges; - } - - @Override - public Set<E> getEdgesFrom(V src) { - return sources.get(src); - } - - @Override - public Set<E> getEdgesTo(V dst) { - return destinations.get(dst); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof MutableAdjacencyListsGraph) { - MutableAdjacencyListsGraph that = (MutableAdjacencyListsGraph) obj; - return this.getClass() == that.getClass() && - Objects.equals(this.vertexes, that.vertexes) && - Objects.equals(this.edges, that.edges); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(vertexes, edges); - } - - @Override - public String toString() { - return toStringHelper(this) - .add("vertexes", vertexes) - .add("edges", edges) - .toString(); - } - - - @Override - public void addVertex(V vertex) { - if (vertexes != null) { - if (!vertexes.contains(vertex)) { - vertexes.add(vertex); - } - } - } - - @Override - public void removeVertex(V vertex) { - if (vertexes != null && edges != null) { - if (vertexes.contains(vertex)) { - vertexes.remove(vertex); - Set<E> srcEdgesList = sources.get(vertex); - Set<E> dstEdgesList = destinations.get(vertex); - edges.removeAll(srcEdgesList); - edges.removeAll(dstEdgesList); - sources.remove(vertex, srcEdgesList); - sources.remove(vertex, dstEdgesList); - } - } - } - - @Override - public void addEdge(E edge) { - if (edges != null) { - if (!edges.contains(edge)) { - edges.add(edge); - sources.put(edge.src(), edge); - destinations.put(edge.dst(), edge); - } - } - } - - @Override - public void removeEdge(E edge) { - if (edges != null) { - if (edges.contains(edge)) { - edges.remove(edge); - sources.remove(edge.src(), edge); - destinations.remove(edge.dst(), edge); - } - } - } - - @Override - public Graph<V, E> toImmutable() { - return null; - } - - /** - * Clear the graph. - */ - public void clear() { - edges.clear(); - vertexes.clear(); - sources.clear(); - destinations.clear(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutableGraph.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutableGraph.java deleted file mode 100644 index bd2b600c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutableGraph.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -/** - * Abstraction of a mutable graph that can be constructed gradually. - */ -public interface MutableGraph<V extends Vertex, E extends Edge> extends Graph<V, E> { - - /** - * Adds the specified vertex to this graph. - * - * @param vertex new vertex - */ - void addVertex(V vertex); - - /** - * Removes the specified vertex from the graph. - * - * @param vertex vertex to be removed - */ - void removeVertex(V vertex); - - /** - * Adds the specified edge to this graph. If the edge vertexes are not - * already in the graph, they will be added as well. - * - * @param edge new edge - */ - void addEdge(E edge); - - /** - * Removes the specified edge from the graph. - * - * @param edge edge to be removed - */ - void removeEdge(E edge); - - /** - * Returns an immutable copy of this graph. - * - * @return immutable copy - */ - Graph<V, E> toImmutable(); - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutablePath.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutablePath.java deleted file mode 100644 index 5cd8fd0e..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/MutablePath.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -/** - * Abstraction of a mutable path that allows gradual construction. - */ -public interface MutablePath<V extends Vertex, E extends Edge<V>> extends Path<V, E> { - - /** - * Inserts a new edge at the beginning of this path. The edge must be - * adjacent to the prior start of the path. - * - * @param edge edge to be inserted - */ - void insertEdge(E edge); - - /** - * Appends a new edge at the end of the this path. The edge must be - * adjacent to the prior end of the path. - * - * @param edge edge to be inserted - */ - void appendEdge(E edge); - - /** - * Removes the specified edge. This edge must be either at the start or - * at the end of the path, or it must be a cyclic edge in order not to - * violate the contiguous path property. - * - * @param edge edge to be removed - */ - void removeEdge(E edge); - - /** - * Sets the total path cost as a unit-less double. - * - * @param cost new path cost - */ - void setCost(double cost); - - /** - * Returns an immutable copy of this path. - * - * @return immutable copy - */ - Path<V, E> toImmutable(); - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Path.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Path.java deleted file mode 100644 index ed9aa2c9..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Path.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.List; - -/** - * Representation of a path in a graph as a sequence of edges. Paths are - * assumed to be continuous, where adjacent edges must share a vertex. - * - * @param <V> vertex type - * @param <E> edge type - */ -public interface Path<V extends Vertex, E extends Edge<V>> extends Edge<V> { - - /** - * Returns the list of edges comprising the path. Adjacent edges will - * share the same vertex, meaning that a source of one edge, will be the - * same as the destination of the prior edge. - * - * @return list of path edges - */ - List<E> edges(); - - /** - * Returns the total cost of the path as a unit-less number. - * - * @return path cost as a unit-less number - */ - double cost(); - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SrlgGraphSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SrlgGraphSearch.java deleted file mode 100644 index fa3d0ddf..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SrlgGraphSearch.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - - -import java.util.Map; -import java.util.List; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.Random; - - -/** - * SRLG Graph Search finds a pair of paths with disjoint risk groups; i.e - * if one path goes through an edge in risk group 1, the other path will go - * through no edges in risk group 1. - */ -public class SrlgGraphSearch<V extends Vertex, E extends Edge<V>> - extends AbstractGraphPathSearch<V, E> { - - static final int ITERATIONS = 100; - static final int POPSIZE = 50; - - boolean useSuurballe = false; - - static final double INF = 100000000.0; - - int numGroups; - Map<E, Integer> riskGrouping; - - Graph<V, E> orig; - V src, dst; - EdgeWeight<V, E> weight; - - /** - * Creates an SRLG graph search object with the given number - * of groups and given risk mapping. - * - * @param groups the number of disjoint risk groups - * @param grouping map linking edges to integral group assignments - */ - public SrlgGraphSearch(int groups, Map<E, Integer> grouping) { - numGroups = groups; - riskGrouping = grouping; - } - - /** - * Creates an SRLG graph search object from a map, inferring - * the number of groups and creating an integral mapping. - * - * @param grouping map linking edges to object group assignments, - * with same-group status linked to equality - */ - public SrlgGraphSearch(Map<E, Object> grouping) { - if (grouping == null) { - useSuurballe = true; - return; - } - numGroups = 0; - HashMap<Object, Integer> tmpMap = new HashMap<>(); - riskGrouping = new HashMap<>(); - for (E key: grouping.keySet()) { - Object value = grouping.get(key); - if (!tmpMap.containsKey(value)) { - tmpMap.put(value, numGroups); - numGroups++; - } - riskGrouping.put(key, tmpMap.get(value)); - } - } - - @Override - public Result<V, E> search(Graph<V, E> graph, V src, V dst, - EdgeWeight<V, E> weight, int maxPaths) { - if (maxPaths == ALL_PATHS) { - maxPaths = POPSIZE; - } - if (useSuurballe) { - return new SuurballeGraphSearch<V, E>().search(graph, src, dst, weight, ALL_PATHS); - } - if (weight == null) { - weight = edge -> 1; - } - checkArguments(graph, src, dst); - orig = graph; - this.src = src; - this.dst = dst; - this.weight = weight; - List<Subset> best = new GAPopulation<Subset>() - .runGA(ITERATIONS, POPSIZE, maxPaths, new Subset(new boolean[numGroups])); - Set<DisjointPathPair> dpps = new HashSet<DisjointPathPair>(); - for (Subset s: best) { - dpps.addAll(s.buildPaths()); - } - Result<V, E> firstDijkstra = new DijkstraGraphSearch<V, E>() - .search(orig, src, dst, weight, 1); - return new Result<V, E>() { - final DefaultResult search = (DefaultResult) firstDijkstra; - - public V src() { - return src; - } - public V dst() { - return dst; - - } - public Set<Path<V, E>> paths() { - Set<Path<V, E>> pathsD = new HashSet<>(); - for (DisjointPathPair<V, E> path: dpps) { - pathsD.add(path); - } - return pathsD; - } - public Map<V, Double> costs() { - return search.costs(); - - } - public Map<V, Set<E>> parents() { - return search.parents(); - - } - }; - } - - //finds the shortest path in the graph given a subset of edge types to use - private Result<V, E> findShortestPathFromSubset(boolean[] subset) { - Graph<V, E> graph = orig; - EdgeWeight<V, E> modified = new EdgeWeight<V, E>() { - final boolean[] subsetF = subset; - - @Override - public double weight(E edge) { - if (subsetF[riskGrouping.get(edge)]) { - return weight.weight(edge); - } - return INF; - } - }; - - Result<V, E> res = new DijkstraGraphSearch<V, E>().search(graph, src, dst, modified, 1); - return res; - } - /** - * A subset is a type of GA organism that represents a subset of allowed shortest - * paths (and its complement). Its fitness is determined by the sum of the weights - * of the first two shortest paths. - */ - class Subset implements GAOrganism { - - boolean[] subset; - boolean[] not; - Random r = new Random(); - - /** - * Creates a Subset from the given subset array. - * - * @param sub subset array - */ - public Subset(boolean[] sub) { - subset = sub.clone(); - not = new boolean[subset.length]; - for (int i = 0; i < subset.length; i++) { - not[i] = !subset[i]; - } - } - - @Override - public double fitness() { - Set<Path<V, E>> paths1 = findShortestPathFromSubset(subset).paths(); - Set<Path<V, E>> paths2 = findShortestPathFromSubset(not).paths(); - if (paths1.size() == 0 || paths2.size() == 0) { - return INF; - } - return paths1.iterator().next().cost() + paths2.iterator().next().cost(); - } - - @Override - public void mutate() { - int turns = r.nextInt((int) Math.sqrt(subset.length)); - while (turns > 0) { - int choose = r.nextInt(subset.length); - subset[choose] = !subset[choose]; - not[choose] = !not[choose]; - turns--; - } - } - - @Override - public GAOrganism crossWith(GAOrganism org) { - if (!(org.getClass().equals(getClass()))) { - return this; - } - Subset other = (Subset) (org); - boolean[] sub = new boolean[subset.length]; - for (int i = 0; i < subset.length; i++) { - sub[i] = subset[i]; - if (r.nextBoolean()) { - sub[i] = other.subset[i]; - } - } - return new Subset(sub); - } - - @Override - public GAOrganism random() { - boolean[] sub = new boolean[subset.length]; - for (int i = 0; i < sub.length; i++) { - sub[i] = r.nextBoolean(); - } - return new Subset(sub); - } - - /** - * Builds the set of disjoint path pairs for a given subset - * using Dijkstra's algorithm on both the subset and complement - * and returning all pairs with one from each set. - * - * @return all shortest disjoint paths given this subset - */ - public Set<DisjointPathPair> buildPaths() { - Set<DisjointPathPair> dpps = new HashSet<>(); - for (Path<V, E> path1: findShortestPathFromSubset(subset).paths()) { - if (path1.cost() >= INF) { - continue; - } - for (Path<V, E> path2: findShortestPathFromSubset(not).paths()) { - if (path2.cost() >= INF) { - continue; - } - DisjointPathPair<V, E> dpp = new DisjointPathPair<>(path1, path2); - dpps.add(dpp); - } - } - return dpps; - } - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java deleted file mode 100644 index 76591c82..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/SuurballeGraphSearch.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.ArrayList; -import java.util.Set; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.HashSet; -import java.util.stream.Collectors; - -/** - * Suurballe shortest-path graph search algorithm capable of finding both - * a shortest path, as well as a backup shortest path, between a source and a destination - * such that the sum of the path lengths is minimized. - */ -public class SuurballeGraphSearch<V extends Vertex, E extends Edge<V>> extends DijkstraGraphSearch<V, E> { - - @Override - public Result<V, E> search(Graph<V, E> graph, V src, V dst, - EdgeWeight<V, E> weight, int maxPaths) { - - if (weight == null) { - weight = edge -> 1; - } - - List<DisjointPathPair<V, E>> dpps = new ArrayList<>(); - - final EdgeWeight weightf = weight; - DefaultResult firstDijkstraS = (DefaultResult) super.search(graph, src, dst, weight, ALL_PATHS); - DefaultResult firstDijkstra = (DefaultResult) super.search(graph, src, null, weight, ALL_PATHS); - - //choose an arbitrary shortest path to run Suurballe on - Path<V, E> shortPath = null; - if (firstDijkstraS.paths().size() == 0) { - return firstDijkstraS; - } - for (Path p: firstDijkstraS.paths()) { - shortPath = p; - //transforms the graph so tree edges have 0 weight - EdgeWeight<V, Edge<V>> modified = edge -> { - if (classE().isInstance(edge)) { - return weightf.weight((E) (edge)) + firstDijkstra.cost(edge.src()) - - firstDijkstra.cost(edge.dst()); - } - return 0; - }; - EdgeWeight<V, E> modified2 = edge -> - weightf.weight(edge) + firstDijkstra.cost(edge.src()) - firstDijkstra.cost(edge.dst()); - - //create a residual graph g' by removing all src vertices and reversing 0 length path edges - MutableGraph<V, Edge<V>> gt = mutableCopy(graph); - - Map<Edge<V>, E> revToEdge = new HashMap<>(); - graph.getEdgesTo(src).forEach(gt::removeEdge); - for (E edge: shortPath.edges()) { - gt.removeEdge(edge); - Edge<V> reverse = new Edge<V>() { - final Edge<V> orig = edge; - public V src() { - return orig.dst(); - } - public V dst() { - return orig.src(); - } - public String toString() { - return "ReversedEdge " + "src=" + src() + " dst=" + dst(); - } - }; - revToEdge.put(reverse, edge); - gt.addEdge(reverse); - } - - //rerun dijkstra on the temporary graph to get a second path - Result<V, Edge<V>> secondDijkstra; - secondDijkstra = new DijkstraGraphSearch<V, Edge<V>>().search(gt, src, dst, modified, ALL_PATHS); - - Path<V, Edge<V>> residualShortPath = null; - if (secondDijkstra.paths().size() == 0) { - dpps.add(new DisjointPathPair<V, E>(shortPath, null)); - continue; - } - - for (Path p2: secondDijkstra.paths()) { - residualShortPath = p2; - - MutableGraph<V, E> roundTrip = mutableCopy(graph); - - List<E> tmp = roundTrip.getEdges().stream().collect(Collectors.toList()); - - tmp.forEach(roundTrip::removeEdge); - - shortPath.edges().forEach(roundTrip::addEdge); - - if (residualShortPath != null) { - for (Edge<V> edge: residualShortPath.edges()) { - if (classE().isInstance(edge)) { - roundTrip.addEdge((E) edge); - } else { - roundTrip.removeEdge(revToEdge.get(edge)); - } - } - } - //Actually build the final result - DefaultResult lastSearch = (DefaultResult) super.search(roundTrip, src, dst, weight, ALL_PATHS); - Path<V, E> path1 = lastSearch.paths().iterator().next(); - path1.edges().forEach(roundTrip::removeEdge); - - Set<Path<V, E>> bckpaths = super.search(roundTrip, src, dst, weight, ALL_PATHS).paths(); - Path<V, E> backup = null; - if (bckpaths.size() != 0) { - backup = bckpaths.iterator().next(); - } - - dpps.add(new DisjointPathPair<>(path1, backup)); - } - } - - for (int i = dpps.size() - 1; i > 0; i--) { - if (dpps.get(i).size() <= 1) { - dpps.remove(i); - } - } - - return new Result<V, E>() { - final DefaultResult search = firstDijkstra; - - public V src() { - return src; - } - public V dst() { - return dst; - } - public Set<Path<V, E>> paths() { - Set<Path<V, E>> pathsD = new HashSet<>(); - int paths = 0; - for (DisjointPathPair<V, E> path: dpps) { - pathsD.add((Path<V, E>) path); - paths++; - if (paths == maxPaths) { - break; - } - } - return pathsD; - } - public Map<V, Double> costs() { - return search.costs(); - } - public Map<V, Set<E>> parents() { - return search.parents(); - } - }; - } - - private Class<?> clazzV; - - public Class<?> classV() { - return clazzV; - } - - private Class<?> clazzE; - - public Class<?> classE() { - return clazzE; - } - /** - * Creates a mutable copy of an immutable graph. - * - * @param graph immutable graph - * @return mutable copy - */ - public MutableGraph mutableCopy(Graph<V, E> graph) { - clazzV = graph.getVertexes().iterator().next().getClass(); - clazzE = graph.getEdges().iterator().next().getClass(); - return new MutableAdjacencyListsGraph<V, E>(graph.getVertexes(), graph.getEdges()); - } -} - diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/TarjanGraphSearch.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/TarjanGraphSearch.java deleted file mode 100644 index 1c436d94..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/TarjanGraphSearch.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Tarjan algorithm for searching a graph and producing results describing - * the graph SCC (strongly-connected components). - */ -public class TarjanGraphSearch<V extends Vertex, E extends Edge<V>> - implements GraphSearch<V, E> { - - /** - * {@inheritDoc} - * <p> - * This implementation produces results augmented with information on - * SCCs within the graph. - * </p> - * <p> - * To prevent traversal of an edge, the {@link EdgeWeight#weight} should - * return a negative value as an edge weight. - * </p> - */ - @Override - public SccResult<V, E> search(Graph<V, E> graph, EdgeWeight<V, E> weight) { - SccResult<V, E> result = new SccResult<>(graph); - for (V vertex : graph.getVertexes()) { - VertexData data = result.data(vertex); - if (data == null) { - connect(graph, vertex, weight, result); - } - } - return result.build(); - } - - /** - * Scans the specified graph, using recursion, and produces SCC results. - * - * @param graph graph to search - * @param vertex current vertex to scan and connect - * @param weight optional edge weight - * @param result graph search result - * @return augmentation vertexData for the current vertex - */ - private VertexData<V> connect(Graph<V, E> graph, V vertex, - EdgeWeight<V, E> weight, - SccResult<V, E> result) { - VertexData<V> data = result.addData(vertex); - - // Scan through all egress edges of the current vertex. - for (E edge : graph.getEdgesFrom(vertex)) { - V nextVertex = edge.dst(); - - // If edge weight is negative, skip it. - if (weight != null && weight.weight(edge) < 0) { - continue; - } - - // Attempt to get the augmentation vertexData for the next vertex. - VertexData<V> nextData = result.data(nextVertex); - if (nextData == null) { - // Next vertex has not been visited yet, so do this now. - nextData = connect(graph, nextVertex, weight, result); - data.lowLink = Math.min(data.lowLink, nextData.lowLink); - - } else if (result.visited(nextData)) { - // Next vertex has been visited, which means it is in the - // same cluster as the current vertex. - data.lowLink = Math.min(data.lowLink, nextData.index); - } - } - - if (data.lowLink == data.index) { - result.addCluster(data); - } - return data; - } - - /** - * Graph search result augmented with SCC vertexData. - */ - public static final class SccResult<V extends Vertex, E extends Edge<V>> - implements Result { - - private final Graph<V, E> graph; - private List<Set<V>> clusterVertexes = new ArrayList<>(); - private List<Set<E>> clusterEdges = new ArrayList<>(); - - private int index = 0; - private final Map<V, VertexData<V>> vertexData = new HashMap<>(); - private final List<VertexData<V>> visited = new ArrayList<>(); - - private SccResult(Graph<V, E> graph) { - this.graph = graph; - } - - /** - * Returns the number of SCC clusters in the graph. - * - * @return number of clusters - */ - public int clusterCount() { - return clusterEdges.size(); - } - - /** - * Returns the list of strongly connected vertex clusters. - * - * @return list of strongly connected vertex sets - */ - public List<Set<V>> clusterVertexes() { - return clusterVertexes; - } - - /** - * Returns the list of edges linking strongly connected vertex clusters. - * - * @return list of strongly connected edge sets - */ - public List<Set<E>> clusterEdges() { - return clusterEdges; - } - - // Gets the augmentation vertexData for the specified vertex - private VertexData<V> data(V vertex) { - return vertexData.get(vertex); - } - - // Adds augmentation vertexData for the specified vertex - private VertexData<V> addData(V vertex) { - VertexData<V> d = new VertexData<>(vertex, index); - vertexData.put(vertex, d); - visited.add(0, d); - index++; - return d; - } - - // Indicates whether the given vertex has been visited - private boolean visited(VertexData data) { - return visited.contains(data); - } - - // Adds a new cluster for the specified vertex - private void addCluster(VertexData data) { - Set<V> vertexes = findClusterVertices(data); - clusterVertexes.add(vertexes); - clusterEdges.add(findClusterEdges(vertexes)); - } - - private Set<V> findClusterVertices(VertexData data) { - VertexData<V> nextVertexData; - Set<V> vertexes = new HashSet<>(); - do { - nextVertexData = visited.remove(0); - vertexes.add(nextVertexData.vertex); - } while (data != nextVertexData); - return Collections.unmodifiableSet(vertexes); - } - - private Set<E> findClusterEdges(Set<V> vertexes) { - Set<E> edges = new HashSet<>(); - for (V vertex : vertexes) { - for (E edge : graph.getEdgesFrom(vertex)) { - if (vertexes.contains((edge.dst()))) { - edges.add(edge); - } - } - } - return Collections.unmodifiableSet(edges); - } - - public SccResult<V, E> build() { - clusterVertexes = Collections.unmodifiableList(clusterVertexes); - clusterEdges = Collections.unmodifiableList(clusterEdges); - return this; - } - } - - // Augments the vertex to assist in determining SCC clusters. - private static final class VertexData<V extends Vertex> { - final V vertex; - int index; - int lowLink; - - private VertexData(V vertex, int index) { - this.vertex = vertex; - this.index = index; - this.lowLink = index; - } - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Vertex.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Vertex.java deleted file mode 100644 index 80e3e7df..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/Vertex.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -/** - * Representation of a graph vertex. - */ -public interface Vertex { -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/package-info.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/package-info.java deleted file mode 100644 index 2ee949d2..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/graph/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Graph abstractions and graph path finding algorithms. - */ -package org.onlab.graph; diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/EventMetric.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/EventMetric.java deleted file mode 100644 index d20ca53f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/EventMetric.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.metrics; - -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Meter; - -/** - * Metric measurements for events. - */ -public class EventMetric { - private static final String GAUGE_TIMESTAMP_NAME = "Timestamp.EpochMs"; - private static final String METER_RATE_NAME = "Rate"; - - private final MetricsService metricsService; - private final String componentName; - private final String featureName; - - private MetricsComponent metricsComponent; - private MetricsFeature metricsFeature; - - private volatile long lastEventTimestampEpochMs = 0; - private Gauge<Long> lastEventTimestampGauge; - private Meter eventRateMeter; - - /** - * Constructor. - * - * @param metricsService the Metrics Service to use for Metrics - * registration and deregistration - * @param componentName the Metrics Component Name to use for Metrics - * registration and deregistration - * @param featureName the Metrics Feature Name to use for Metrics - * registration and deregistration - */ - public EventMetric(MetricsService metricsService, String componentName, - String featureName) { - this.metricsService = metricsService; - this.componentName = componentName; - this.featureName = featureName; - } - - /** - * Registers the metrics. - */ - public void registerMetrics() { - metricsComponent = metricsService.registerComponent(componentName); - metricsFeature = metricsComponent.registerFeature(featureName); - - lastEventTimestampEpochMs = 0; - lastEventTimestampGauge = - metricsService.registerMetric(metricsComponent, - metricsFeature, - GAUGE_TIMESTAMP_NAME, - new Gauge<Long>() { - @Override - public Long getValue() { - return lastEventTimestampEpochMs; - } - }); - - eventRateMeter = metricsService.createMeter(metricsComponent, - metricsFeature, - METER_RATE_NAME); - } - - /** - * Removes the metrics. - */ - public void removeMetrics() { - lastEventTimestampEpochMs = 0; - metricsService.removeMetric(metricsComponent, - metricsFeature, - GAUGE_TIMESTAMP_NAME); - metricsService.removeMetric(metricsComponent, - metricsFeature, - METER_RATE_NAME); - } - - /** - * Updates the metric measurements for a single event. - */ - public void eventReceived() { - lastEventTimestampEpochMs = System.currentTimeMillis(); - eventRateMeter.mark(1); - } - - /** - * Gets the last event timestamp Gauge (ms from the Epoch). - * - * @return the last event timestamp Gauge (ms from the Epoch) - */ - public Gauge<Long> lastEventTimestampGauge() { - return lastEventTimestampGauge; - } - - /** - * Gets the event rate meter. - * - * @return the event rate meter - */ - public Meter eventRateMeter() { - return eventRateMeter; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsComponent.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsComponent.java deleted file mode 100644 index cc8fe83c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsComponent.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.metrics; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * Components to register for metrics. - */ -public class MetricsComponent implements MetricsComponentRegistry { - private final String name; - - /** - * Registry to hold the Features defined in this Component. - */ - private final ConcurrentMap<String, MetricsFeature> featuresRegistry = - new ConcurrentHashMap<>(); - - /** - * Constructs a component from a name. - * - * @param newName name of the component - */ - MetricsComponent(final String newName) { - name = newName; - } - - @Override - public String getName() { - return name; - } - - @Override - public MetricsFeature registerFeature(final String featureName) { - MetricsFeature feature = featuresRegistry.get(featureName); - if (feature == null) { - final MetricsFeature createdFeature = - new MetricsFeature(featureName); - feature = featuresRegistry.putIfAbsent(featureName, createdFeature); - if (feature == null) { - feature = createdFeature; - } - } - return feature; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsComponentRegistry.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsComponentRegistry.java deleted file mode 100644 index 89f6ec5e..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsComponentRegistry.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.metrics; - -/** - * Registry Entry for Metrics Components. - */ -public interface MetricsComponentRegistry { - /** - * Fetches the name of the Component. - * - * @return name of the Component - */ - String getName(); - - /** - * Registers a Feature for this component. - * - * @param featureName name of the Feature to register - * @return Feature object that can be used when creating Metrics - */ - MetricsFeature registerFeature(String featureName); -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsFeature.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsFeature.java deleted file mode 100644 index bc6753c9..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsFeature.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.metrics; - -/** - * Features to tag metrics. - */ -public class MetricsFeature { - private final String name; - - /** - * Constructs a Feature from a name. - * - * @param newName name of the Feature - */ - public MetricsFeature(final String newName) { - name = newName; - } - - /** - * Fetches the name of the Feature. - * - * @return name of the Feature - */ - public String getName() { - return name; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsManager.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsManager.java deleted file mode 100644 index 6c9314ad..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsManager.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.metrics; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; - -/** - * This class holds the Metrics registry for ONOS. - * All metrics (Counter, Histogram, Timer, Meter, Gauge) use a hierarchical - * string-based naming scheme: COMPONENT.FEATURE.NAME. - * Example: "Topology.Counters.TopologyUpdates". - * The COMPONENT and FEATURE names have to be registered in advance before - * a metric can be created. Example: - * <pre> - * <code> - * private final MetricsManager.MetricsComponent COMPONENT = - * MetricsManager.registerComponent("Topology"); - * private final MetricsManager.MetricsFeature FEATURE = - * COMPONENT.registerFeature("Counters"); - * private final Counter counterTopologyUpdates = - * MetricsManager.createCounter(COMPONENT, FEATURE, "TopologyUpdates"); - * </code> - * </pre> - * Gauges are slightly different because they are not created directly in - * this class, but are allocated by the caller and passed in for registration: - * <pre> - * <code> - * private final Gauge<Long> gauge = - * new {@literal Gauge<Long>}() { - * {@literal @}Override - * public Long getValue() { - * return gaugeValue; - * } - * }; - * MetricsManager.registerMetric(COMPONENT, FEATURE, GAUGE_NAME, gauge); - * </code> - * </pre> - */ -public class MetricsManager implements MetricsService { - - /** - * Registry to hold the Components defined in the system. - */ - private ConcurrentMap<String, MetricsComponent> componentsRegistry = - new ConcurrentHashMap<>(); - - /** - * Registry for the Metrics objects created in the system. - */ - private MetricRegistry metricsRegistry = new MetricRegistry(); - - /** - * Clears the internal state. - */ - protected void clear() { - this.componentsRegistry = new ConcurrentHashMap<>(); - this.metricsRegistry = new MetricRegistry(); - } - - /** - * Registers a component. - * - * @param name name of the Component to register - * @return MetricsComponent object that can be used to create Metrics. - */ - @Override - public MetricsComponent registerComponent(final String name) { - MetricsComponent component = componentsRegistry.get(name); - if (component == null) { - final MetricsComponent createdComponent = - new MetricsComponent(name); - component = componentsRegistry.putIfAbsent(name, createdComponent); - if (component == null) { - component = createdComponent; - } - } - return component; - } - - /** - * Generates a name for a Metric from its component and feature. - * - * @param component component the metric is defined in - * @param feature feature the metric is defined in - * @param metricName local name of the metric - * - * @return full name of the metric - */ - private String generateName(final MetricsComponent component, - final MetricsFeature feature, - final String metricName) { - return MetricRegistry.name(component.getName(), - feature.getName(), - metricName); - } - - /** - * Creates a Counter metric. - * - * @param component component the Counter is defined in - * @param feature feature the Counter is defined in - * @param metricName local name of the metric - * @return the created Counter Meteric - */ - @Override - public Counter createCounter(final MetricsComponent component, - final MetricsFeature feature, - final String metricName) { - final String name = generateName(component, feature, metricName); - return metricsRegistry.counter(name); - } - - /** - * Creates a Histogram metric. - * - * @param component component the Histogram is defined in - * @param feature feature the Histogram is defined in - * @param metricName local name of the metric - * @return the created Histogram Metric - */ - @Override - public Histogram createHistogram(final MetricsComponent component, - final MetricsFeature feature, - final String metricName) { - final String name = generateName(component, feature, metricName); - return metricsRegistry.histogram(name); - } - - /** - * Creates a Timer metric. - * - * @param component component the Timer is defined in - * @param feature feature the Timer is defined in - * @param metricName local name of the metric - * @return the created Timer Metric - */ - @Override - public Timer createTimer(final MetricsComponent component, - final MetricsFeature feature, - final String metricName) { - final String name = generateName(component, feature, metricName); - return metricsRegistry.timer(name); - } - - /** - * Creates a Meter metric. - * - * @param component component the Meter is defined in - * @param feature feature the Meter is defined in - * @param metricName local name of the metric - * @return the created Meter Metric - */ - @Override - public Meter createMeter(final MetricsComponent component, - final MetricsFeature feature, - final String metricName) { - final String name = generateName(component, feature, metricName); - return metricsRegistry.meter(name); - } - - /** - * Registers an already created Metric. This is used for situation where a - * caller needs to allocate its own Metric, but still register it with the - * system. - * - * @param <T> Metric type - * @param component component the Metric is defined in - * @param feature feature the Metric is defined in - * @param metricName local name of the metric - * @param metric Metric to register - * @return the registered Metric - */ - @Override - public <T extends Metric> T registerMetric( - final MetricsComponent component, - final MetricsFeature feature, - final String metricName, - final T metric) { - final String name = generateName(component, feature, metricName); - metricsRegistry.register(name, metric); - return metric; - } - - /** - * Removes the metric with the given name. - * - * @param component component the Metric is defined in - * @param feature feature the Metric is defined in - * @param metricName local name of the metric - * @return true if the metric existed and was removed, otherwise false - */ - @Override - public boolean removeMetric(final MetricsComponent component, - final MetricsFeature feature, - final String metricName) { - final String name = generateName(component, feature, metricName); - return metricsRegistry.remove(name); - } - - /** - * Fetches the existing Timers. - * - * @param filter filter to use to select Timers - * @return a map of the Timers that match the filter, with the key as the - * name String to the Timer. - */ - @Override - public Map<String, Timer> getTimers(final MetricFilter filter) { - return metricsRegistry.getTimers(filter); - } - - /** - * Fetches the existing Gauges. - * - * @param filter filter to use to select Gauges - * @return a map of the Gauges that match the filter, with the key as the - * name String to the Gauge. - */ - @Override - public Map<String, Gauge> getGauges(final MetricFilter filter) { - return metricsRegistry.getGauges(filter); - } - - /** - * Fetches the existing Counters. - * - * @param filter filter to use to select Counters - * @return a map of the Counters that match the filter, with the key as the - * name String to the Counter. - */ - @Override - public Map<String, Counter> getCounters(final MetricFilter filter) { - return metricsRegistry.getCounters(filter); - } - - /** - * Fetches the existing Meters. - * - * @param filter filter to use to select Meters - * @return a map of the Meters that match the filter, with the key as the - * name String to the Meter. - */ - @Override - public Map<String, Meter> getMeters(final MetricFilter filter) { - return metricsRegistry.getMeters(filter); - } - - /** - * Fetches the existing Histograms. - * - * @param filter filter to use to select Histograms - * @return a map of the Histograms that match the filter, with the key as - * the name String to the Histogram. - */ - @Override - public Map<String, Histogram> getHistograms(final MetricFilter filter) { - return metricsRegistry.getHistograms(filter); - } - - /** - * Removes all Metrics that match a given filter. - * - * @param filter filter to use to select the Metrics to remove. - */ - @Override - public void removeMatching(final MetricFilter filter) { - metricsRegistry.removeMatching(filter); - } - - /** - * Fetches the existing Meters. - * - * - * @return a map of all metrics with the key as the - * name String to the Meter. - */ - public Map<String, Metric> getMetrics() { - return metricsRegistry.getMetrics(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsService.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsService.java deleted file mode 100644 index 4f0d67a8..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsService.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.metrics; - -import java.util.Map; - -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.Timer; - -/** - * Metrics Service to collect metrics. - */ -public interface MetricsService { - - /** - * Registers a component. - * - * @param name name of the Component to register - * @return MetricsComponent object that can be used to create Metrics. - */ - MetricsComponent registerComponent(String name); - - /** - * Creates a Counter metric. - * - * @param component component the Counter is defined in - * @param feature feature the Counter is defined in - * @param metricName local name of the metric - * @return the created Counter Meteric - */ - Counter createCounter(MetricsComponent component, - MetricsFeature feature, - String metricName); - - /** - * Creates a Histogram metric. - * - * @param component component the Histogram is defined in - * @param feature feature the Histogram is defined in - * @param metricName local name of the metric - * @return the created Histogram Metric - */ - Histogram createHistogram(MetricsComponent component, - MetricsFeature feature, - String metricName); - - /** - * Creates a Timer metric. - * - * @param component component the Timer is defined in - * @param feature feature the Timer is defined in - * @param metricName local name of the metric - * @return the created Timer Metric - */ - Timer createTimer(MetricsComponent component, - MetricsFeature feature, - String metricName); - - /** - * Creates a Meter metric. - * - * @param component component the Meter is defined in - * @param feature feature the Meter is defined in - * @param metricName local name of the metric - * @return the created Meter Metric - */ - Meter createMeter(MetricsComponent component, - MetricsFeature feature, - String metricName); - - /** - * Registers an already created Metric. This is used for situation where a - * caller needs to allocate its own Metric, but still register it with the - * system. - * - * @param <T> Metric type - * @param component component the Metric is defined in - * @param feature feature the Metric is defined in - * @param metricName local name of the metric - * @param metric Metric to register - * @return the registered Metric - */ - <T extends Metric> T registerMetric( - MetricsComponent component, - MetricsFeature feature, - String metricName, - T metric); - - /** - * Removes the metric with the given name. - * - * @param component component the Metric is defined in - * @param feature feature the Metric is defined in - * @param metricName local name of the metric - * @return true if the metric existed and was removed, otherwise false - */ - boolean removeMetric(MetricsComponent component, - MetricsFeature feature, - String metricName); - - /** - * Fetches the existing Timers. - * - * @param filter filter to use to select Timers - * @return a map of the Timers that match the filter, with the key as the - * name String to the Timer. - */ - Map<String, Timer> getTimers(MetricFilter filter); - - /** - * Fetches the existing Gauges. - * - * @param filter filter to use to select Gauges - * @return a map of the Gauges that match the filter, with the key as the - * name String to the Gauge. - */ - Map<String, Gauge> getGauges(MetricFilter filter); - - /** - * Fetches the existing Counters. - * - * @param filter filter to use to select Counters - * @return a map of the Counters that match the filter, with the key as the - * name String to the Counter. - */ - Map<String, Counter> getCounters(MetricFilter filter); - - /** - * Fetches the existing Meters. - * - * @param filter filter to use to select Meters - * @return a map of the Meters that match the filter, with the key as the - * name String to the Meter. - */ - Map<String, Meter> getMeters(MetricFilter filter); - - /** - * Fetches the existing Histograms. - * - * @param filter filter to use to select Histograms - * @return a map of the Histograms that match the filter, with the key as - * the name String to the Histogram. - */ - Map<String, Histogram> getHistograms(MetricFilter filter); - - /** - * Fetches the existing metrics. - * - * @return a map of the Metrics, with the key as - * the name String to the Histogram. - */ - Map<String, Metric> getMetrics(); - - /** - * Removes all Metrics that match a given filter. - * - * @param filter filter to use to select the Metrics to remove. - */ - void removeMatching(MetricFilter filter); -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsUtil.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsUtil.java deleted file mode 100644 index cab6c0ea..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/MetricsUtil.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.metrics; - -import com.codahale.metrics.Timer; -import com.codahale.metrics.Timer.Context; - -public final class MetricsUtil { - - /** - * Starts the Metric Timer. - * <p> - * If the given timer was null, it will silently return null. - * </p> - * - * @param timer timer to start - * @return timing context, if timer was not null - */ - public static Context startTimer(Timer timer) { - if (timer != null) { - return timer.time(); - } - return null; - } - - /** - * Stops the Metric Timer context. - * <p> - * If the given context was null, it will silently be ignored. - * </p> - * - * @param context timing context to stop, if not null. - */ - public static void stopTimer(Context context) { - if (context != null) { - context.stop(); - } - } - - // avoid instantiation - private MetricsUtil() {} -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/package-info.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/package-info.java deleted file mode 100644 index 0a61f353..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/metrics/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Misc utils for various performance metrics. - */ -package org.onlab.metrics; diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ARP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ARP.java deleted file mode 100644 index dc3c07f1..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ARP.java +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import static org.onlab.packet.PacketUtils.*; - -/** - * - * - */ -public class ARP extends BasePacket { - public static final short HW_TYPE_ETHERNET = 0x1; - - public static final short PROTO_TYPE_IP = 0x800; - - public static final short OP_REQUEST = 0x1; - public static final short OP_REPLY = 0x2; - public static final short OP_RARP_REQUEST = 0x3; - public static final short OP_RARP_REPLY = 0x4; - - public static final short INITIAL_HEADER_LENGTH = 8; - - protected short hardwareType; - protected short protocolType; - protected byte hardwareAddressLength; - protected byte protocolAddressLength; - protected short opCode; - protected byte[] senderHardwareAddress; - protected byte[] senderProtocolAddress; - protected byte[] targetHardwareAddress; - protected byte[] targetProtocolAddress; - - /** - * @return the hardwareType - */ - public short getHardwareType() { - return this.hardwareType; - } - - /** - * @param hwType - * the hardwareType to set - * @return this - */ - public ARP setHardwareType(final short hwType) { - this.hardwareType = hwType; - return this; - } - - /** - * @return the protocolType - */ - public short getProtocolType() { - return this.protocolType; - } - - /** - * @param protoType - * the protocolType to set - * @return this - */ - public ARP setProtocolType(final short protoType) { - this.protocolType = protoType; - return this; - } - - /** - * @return the hardwareAddressLength - */ - public byte getHardwareAddressLength() { - return this.hardwareAddressLength; - } - - /** - * @param hwAddressLength - * the hardwareAddressLength to set - * @return this - */ - public ARP setHardwareAddressLength(final byte hwAddressLength) { - this.hardwareAddressLength = hwAddressLength; - return this; - } - - /** - * @return the protocolAddressLength - */ - public byte getProtocolAddressLength() { - return this.protocolAddressLength; - } - - /** - * @param protoAddressLength - * the protocolAddressLength to set - * @return this - */ - public ARP setProtocolAddressLength(final byte protoAddressLength) { - this.protocolAddressLength = protoAddressLength; - return this; - } - - /** - * @return the opCode - */ - public short getOpCode() { - return this.opCode; - } - - /** - * @param op - * the opCode to set - * @return this - */ - public ARP setOpCode(final short op) { - this.opCode = op; - return this; - } - - /** - * @return the senderHardwareAddress - */ - public byte[] getSenderHardwareAddress() { - return this.senderHardwareAddress; - } - - /** - * @param senderHWAddress - * the senderHardwareAddress to set - * @return this - */ - public ARP setSenderHardwareAddress(final byte[] senderHWAddress) { - this.senderHardwareAddress = senderHWAddress; - return this; - } - - /** - * @return the senderProtocolAddress - */ - public byte[] getSenderProtocolAddress() { - return this.senderProtocolAddress; - } - - /** - * @param senderProtoAddress - * the senderProtocolAddress to set - * @return this - */ - public ARP setSenderProtocolAddress(final byte[] senderProtoAddress) { - this.senderProtocolAddress = senderProtoAddress; - return this; - } - - public ARP setSenderProtocolAddress(final int address) { - this.senderProtocolAddress = ByteBuffer.allocate(4).putInt(address) - .array(); - return this; - } - - /** - * @return the targetHardwareAddress - */ - public byte[] getTargetHardwareAddress() { - return this.targetHardwareAddress; - } - - /** - * @param targetHWAddress - * the targetHardwareAddress to set - * @return this - */ - public ARP setTargetHardwareAddress(final byte[] targetHWAddress) { - this.targetHardwareAddress = targetHWAddress; - return this; - } - - /** - * @return the targetProtocolAddress - */ - public byte[] getTargetProtocolAddress() { - return this.targetProtocolAddress; - } - - /** - * @return True if gratuitous ARP (SPA = TPA), false otherwise - */ - public boolean isGratuitous() { - assert this.senderProtocolAddress.length == this.targetProtocolAddress.length; - - int indx = 0; - while (indx < this.senderProtocolAddress.length) { - if (this.senderProtocolAddress[indx] != this.targetProtocolAddress[indx]) { - return false; - } - indx++; - } - - return true; - } - - /** - * @param targetProtoAddress - * the targetProtocolAddress to set - * @return this - */ - public ARP setTargetProtocolAddress(final byte[] targetProtoAddress) { - this.targetProtocolAddress = targetProtoAddress; - return this; - } - - public ARP setTargetProtocolAddress(final int address) { - this.targetProtocolAddress = ByteBuffer.allocate(4).putInt(address) - .array(); - return this; - } - - @Override - public byte[] serialize() { - final int length = 8 + 2 * (0xff & this.hardwareAddressLength) + 2 - * (0xff & this.protocolAddressLength); - final byte[] data = new byte[length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - bb.putShort(this.hardwareType); - bb.putShort(this.protocolType); - bb.put(this.hardwareAddressLength); - bb.put(this.protocolAddressLength); - bb.putShort(this.opCode); - bb.put(this.senderHardwareAddress, 0, 0xff & this.hardwareAddressLength); - bb.put(this.senderProtocolAddress, 0, 0xff & this.protocolAddressLength); - bb.put(this.targetHardwareAddress, 0, 0xff & this.hardwareAddressLength); - bb.put(this.targetProtocolAddress, 0, 0xff & this.protocolAddressLength); - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.hardwareType = bb.getShort(); - this.protocolType = bb.getShort(); - this.hardwareAddressLength = bb.get(); - this.protocolAddressLength = bb.get(); - this.opCode = bb.getShort(); - this.senderHardwareAddress = new byte[0xff & this.hardwareAddressLength]; - bb.get(this.senderHardwareAddress, 0, this.senderHardwareAddress.length); - this.senderProtocolAddress = new byte[0xff & this.protocolAddressLength]; - bb.get(this.senderProtocolAddress, 0, this.senderProtocolAddress.length); - this.targetHardwareAddress = new byte[0xff & this.hardwareAddressLength]; - bb.get(this.targetHardwareAddress, 0, this.targetHardwareAddress.length); - this.targetProtocolAddress = new byte[0xff & this.protocolAddressLength]; - bb.get(this.targetProtocolAddress, 0, this.targetProtocolAddress.length); - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 13121; - int result = super.hashCode(); - result = prime * result + this.hardwareAddressLength; - result = prime * result + this.hardwareType; - result = prime * result + this.opCode; - result = prime * result + this.protocolAddressLength; - result = prime * result + this.protocolType; - result = prime * result + Arrays.hashCode(this.senderHardwareAddress); - result = prime * result + Arrays.hashCode(this.senderProtocolAddress); - result = prime * result + Arrays.hashCode(this.targetHardwareAddress); - result = prime * result + Arrays.hashCode(this.targetProtocolAddress); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof ARP)) { - return false; - } - final ARP other = (ARP) obj; - if (this.hardwareAddressLength != other.hardwareAddressLength) { - return false; - } - if (this.hardwareType != other.hardwareType) { - return false; - } - if (this.opCode != other.opCode) { - return false; - } - if (this.protocolAddressLength != other.protocolAddressLength) { - return false; - } - if (this.protocolType != other.protocolType) { - return false; - } - if (!Arrays.equals(this.senderHardwareAddress, - other.senderHardwareAddress)) { - return false; - } - if (!Arrays.equals(this.senderProtocolAddress, - other.senderProtocolAddress)) { - return false; - } - if (!Arrays.equals(this.targetHardwareAddress, - other.targetHardwareAddress)) { - return false; - } - if (!Arrays.equals(this.targetProtocolAddress, - other.targetProtocolAddress)) { - return false; - } - return true; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return "ARP [hardwareType=" + this.hardwareType + ", protocolType=" - + this.protocolType + ", hardwareAddressLength=" - + this.hardwareAddressLength + ", protocolAddressLength=" - + this.protocolAddressLength + ", opCode=" + this.opCode - + ", senderHardwareAddress=" - + Arrays.toString(this.senderHardwareAddress) - + ", senderProtocolAddress=" - + Arrays.toString(this.senderProtocolAddress) - + ", targetHardwareAddress=" - + Arrays.toString(this.targetHardwareAddress) - + ", targetProtocolAddress=" - + Arrays.toString(this.targetProtocolAddress) + "]"; - } - - /** - * Builds an ARP reply based on a request. - * - * @param srcIp the IP address to use as the reply source - * @param srcMac the MAC address to use as the reply source - * @param request the ARP request we got - * @return an Ethernet frame containing the ARP reply - */ - public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac, - Ethernet request) { - - Ethernet eth = new Ethernet(); - eth.setDestinationMACAddress(request.getSourceMAC()); - eth.setSourceMACAddress(srcMac); - eth.setEtherType(Ethernet.TYPE_ARP); - eth.setVlanID(request.getVlanID()); - - ARP arp = new ARP(); - arp.setOpCode(ARP.OP_REPLY); - arp.setProtocolType(ARP.PROTO_TYPE_IP); - arp.setHardwareType(ARP.HW_TYPE_ETHERNET); - - arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH); - arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH); - arp.setSenderHardwareAddress(srcMac.toBytes()); - arp.setTargetHardwareAddress(request.getSourceMACAddress()); - - arp.setTargetProtocolAddress(((ARP) request.getPayload()) - .getSenderProtocolAddress()); - arp.setSenderProtocolAddress(srcIp.toInt()); - - eth.setPayload(arp); - return eth; - } - - /** - * Deserializer function for ARP packets. - * - * @return deserializer function - */ - public static Deserializer<ARP> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, INITIAL_HEADER_LENGTH); - - ARP arp = new ARP(); - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - arp.setHardwareType(bb.getShort()); - arp.setProtocolType(bb.getShort()); - - byte hwAddressLength = bb.get(); - arp.setHardwareAddressLength(hwAddressLength); - - byte protocolAddressLength = bb.get(); - arp.setProtocolAddressLength(protocolAddressLength); - arp.setOpCode(bb.getShort()); - - // Check we have enough space for the addresses - checkHeaderLength(length, INITIAL_HEADER_LENGTH + - 2 * hwAddressLength + - 2 * protocolAddressLength); - - arp.senderHardwareAddress = new byte[0xff & hwAddressLength]; - bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length); - arp.senderProtocolAddress = new byte[0xff & protocolAddressLength]; - bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length); - arp.targetHardwareAddress = new byte[0xff & hwAddressLength]; - bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length); - arp.targetProtocolAddress = new byte[0xff & protocolAddressLength]; - bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length); - - return arp; - }; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/BasePacket.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/BasePacket.java deleted file mode 100644 index 4aece66f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/BasePacket.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * - * - */ -public abstract class BasePacket implements IPacket { - protected IPacket parent; - protected IPacket payload; - - /** - * @return the parent - */ - @Override - public IPacket getParent() { - return this.parent; - } - - /** - * @param parent - * the parent to set - */ - @Override - public IPacket setParent(final IPacket parent) { - this.parent = parent; - return this; - } - - /** - * @return the payload - */ - @Override - public IPacket getPayload() { - return this.payload; - } - - /** - * @param payload - * the payload to set - */ - @Override - public IPacket setPayload(final IPacket payload) { - this.payload = payload; - return this; - } - - @Override - public void resetChecksum() { - if (this.parent != null) { - this.parent.resetChecksum(); - } - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 6733; - int result = 1; - result = prime * result - + (this.payload == null ? 0 : this.payload.hashCode()); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof BasePacket)) { - return false; - } - final BasePacket other = (BasePacket) obj; - if (this.payload == null) { - if (other.payload != null) { - return false; - } - } else if (!this.payload.equals(other.payload)) { - return false; - } - return true; - } - - @Override - public Object clone() { - IPacket pkt; - try { - pkt = this.getClass().newInstance(); - } catch (final Exception e) { - throw new RuntimeException("Could not clone packet"); - } - - final byte[] data = this.serialize(); - pkt.deserialize(this.serialize(), 0, data.length); - pkt.setParent(this.parent); - return pkt; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ChassisId.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ChassisId.java deleted file mode 100644 index 23c9859f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ChassisId.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * The class representing a network device chassisId. - * This class is immutable. - */ -public final class ChassisId { - - private static final long UNKNOWN = 0; - private final long value; - - /** - * Default constructor. - */ - public ChassisId() { - this.value = ChassisId.UNKNOWN; - } - - /** - * Constructor from a long value. - * - * @param value the value to use. - */ - public ChassisId(long value) { - this.value = value; - } - - /** - * Constructor from a string. - * - * @param value the value to use. - */ - public ChassisId(String value) { - this.value = Long.parseLong(value, 16); - } - - /** - * Get the value of the chassis id. - * - * @return the value of the chassis id. - */ - public long value() { - return value; - } - - /** - * Convert the Chassis Id value to a ':' separated hexadecimal string. - * - * @return the Chassis Id value as a ':' separated hexadecimal string. - */ - @Override - public String toString() { - return Long.toHexString(this.value); - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof ChassisId)) { - return false; - } - - ChassisId otherChassisId = (ChassisId) other; - - return value == otherChassisId.value; - } - - @Override - public int hashCode() { - return Long.hashCode(value); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCP.java deleted file mode 100644 index de5b43fa..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCP.java +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * - */ -public class DHCP extends BasePacket { - /** - * Dynamic Host Configuration Protocol packet. - * ------------------------------------------ |op (1) | htype(1) | hlen(1) | - * hops(1) | ------------------------------------------ | xid (4) | - * ------------------------------------------ | secs (2) | flags (2) | - * ------------------------------------------ | ciaddr (4) | - * ------------------------------------------ | yiaddr (4) | - * ------------------------------------------ | siaddr (4) | - * ------------------------------------------ | giaddr (4) | - * ------------------------------------------ | chaddr (16) | - * ------------------------------------------ | sname (64) | - * ------------------------------------------ | file (128) | - * ------------------------------------------ | options (312) | - * ------------------------------------------ - * - */ - // Header + magic without options - public static final int MIN_HEADER_LENGTH = 240; - public static final byte OPCODE_REQUEST = 0x1; - public static final byte OPCODE_REPLY = 0x2; - - public static final byte HWTYPE_ETHERNET = 0x1; - - public enum DHCPOptionCode { - OptionCode_SubnetMask((byte) 1), OptionCode_RouterAddress((byte) 3), OptionCode_DomainServer((byte) 6), - OptionCode_HostName((byte) 12), OptionCode_DomainName((byte) 15), OptionCode_BroadcastAddress((byte) 28), - OptionCode_RequestedIP((byte) 50), OptionCode_LeaseTime((byte) 51), OptionCode_MessageType((byte) 53), - OptionCode_DHCPServerIp((byte) 54), OptionCode_RequestedParameters((byte) 55), - OptionCode_RenewalTime((byte) 58), OPtionCode_RebindingTime((byte) 59), OptionCode_ClientID((byte) 61), - OptionCode_END((byte) 255); - - protected byte value; - - private DHCPOptionCode(final byte value) { - this.value = value; - } - - public byte getValue() { - return this.value; - } - } - - protected byte opCode; - protected byte hardwareType; - protected byte hardwareAddressLength; - protected byte hops; - protected int transactionId; - protected short seconds; - protected short flags; - protected int clientIPAddress; - protected int yourIPAddress; - protected int serverIPAddress; - protected int gatewayIPAddress; - protected byte[] clientHardwareAddress; - protected String serverName; - protected String bootFileName; - protected List<DHCPOption> options = new ArrayList<DHCPOption>(); - - /** - * @return the opCode - */ - public byte getOpCode() { - return this.opCode; - } - - /** - * @param opCode - * the opCode to set - * @return this - */ - public DHCP setOpCode(final byte opCode) { - this.opCode = opCode; - return this; - } - - /** - * @return the hardwareType - */ - public byte getHardwareType() { - return this.hardwareType; - } - - /** - * @param hardwareType - * the hardwareType to set - * @return this - */ - public DHCP setHardwareType(final byte hardwareType) { - this.hardwareType = hardwareType; - return this; - } - - /** - * @return the hardwareAddressLength - */ - public byte getHardwareAddressLength() { - return this.hardwareAddressLength; - } - - /** - * @param hardwareAddressLength - * the hardwareAddressLength to set - * @return this - */ - public DHCP setHardwareAddressLength(final byte hardwareAddressLength) { - this.hardwareAddressLength = hardwareAddressLength; - return this; - } - - /** - * @return the hops - */ - public byte getHops() { - return this.hops; - } - - /** - * @param hops - * the hops to set - * @return this - */ - public DHCP setHops(final byte hops) { - this.hops = hops; - return this; - } - - /** - * @return the transactionId - */ - public int getTransactionId() { - return this.transactionId; - } - - /** - * @param transactionId - * the transactionId to set - * @return this - */ - public DHCP setTransactionId(final int transactionId) { - this.transactionId = transactionId; - return this; - } - - /** - * @return the seconds - */ - public short getSeconds() { - return this.seconds; - } - - /** - * @param seconds - * the seconds to set - * @return this - */ - public DHCP setSeconds(final short seconds) { - this.seconds = seconds; - return this; - } - - /** - * @return the flags - */ - public short getFlags() { - return this.flags; - } - - /** - * @param flags - * the flags to set - * @return this - */ - public DHCP setFlags(final short flags) { - this.flags = flags; - return this; - } - - /** - * @return the clientIPAddress - */ - public int getClientIPAddress() { - return this.clientIPAddress; - } - - /** - * @param clientIPAddress - * the clientIPAddress to set - * @return this - */ - public DHCP setClientIPAddress(final int clientIPAddress) { - this.clientIPAddress = clientIPAddress; - return this; - } - - /** - * @return the yourIPAddress - */ - public int getYourIPAddress() { - return this.yourIPAddress; - } - - /** - * @param yourIPAddress - * the yourIPAddress to set - * @return this - */ - public DHCP setYourIPAddress(final int yourIPAddress) { - this.yourIPAddress = yourIPAddress; - return this; - } - - /** - * @return the serverIPAddress - */ - public int getServerIPAddress() { - return this.serverIPAddress; - } - - /** - * @param serverIPAddress - * the serverIPAddress to set - * @return this - */ - public DHCP setServerIPAddress(final int serverIPAddress) { - this.serverIPAddress = serverIPAddress; - return this; - } - - /** - * @return the gatewayIPAddress - */ - public int getGatewayIPAddress() { - return this.gatewayIPAddress; - } - - /** - * @param gatewayIPAddress - * the gatewayIPAddress to set - * @return this - */ - public DHCP setGatewayIPAddress(final int gatewayIPAddress) { - this.gatewayIPAddress = gatewayIPAddress; - return this; - } - - /** - * @return the clientHardwareAddress - */ - public byte[] getClientHardwareAddress() { - return this.clientHardwareAddress; - } - - /** - * @param clientHardwareAddress - * the clientHardwareAddress to set - * @return this - */ - public DHCP setClientHardwareAddress(final byte[] clientHardwareAddress) { - this.clientHardwareAddress = clientHardwareAddress; - return this; - } - - /** - * Gets a specific DHCP option parameter. - * - * @param optionCode - * The option code to get - * @return The value of the option if it exists, null otherwise - */ - public DHCPOption getOption(final DHCPOptionCode optionCode) { - for (final DHCPOption opt : this.options) { - if (opt.code == optionCode.value) { - return opt; - } - } - return null; - } - - /** - * @return the options - */ - public List<DHCPOption> getOptions() { - return this.options; - } - - /** - * @param options - * the options to set - * @return this - */ - public DHCP setOptions(final List<DHCPOption> options) { - this.options = options; - return this; - } - - /** - * @return the packetType base on option 53 - */ - public DHCPPacketType getPacketType() { - final ListIterator<DHCPOption> lit = this.options.listIterator(); - while (lit.hasNext()) { - final DHCPOption option = lit.next(); - // only care option 53 - if (option.getCode() == 53) { - return DHCPPacketType.getType(option.getData()[0]); - } - } - return null; - } - - /** - * @return the serverName - */ - public String getServerName() { - return this.serverName; - } - - /** - * @param server - * the serverName to set - * @return this - */ - public DHCP setServerName(final String server) { - this.serverName = server; - return this; - } - - /** - * @return the bootFileName - */ - public String getBootFileName() { - return this.bootFileName; - } - - /** - * @param bootFile - * the bootFileName to set - * @return this - */ - public DHCP setBootFileName(final String bootFile) { - this.bootFileName = bootFile; - return this; - } - - @Override - public byte[] serialize() { - // not guaranteed to retain length/exact format - this.resetChecksum(); - - // minimum size 240 including magic cookie, options generally padded to - // 300 - int optionsLength = 0; - for (final DHCPOption option : this.options) { - if (option.getCode() == 0 || option.getCode() == ((byte) 255)) { - optionsLength += 1; - } else { - optionsLength += 2 + (0xff & option.getLength()); - } - } - int optionsPadLength = 0; - if (optionsLength < 60) { - optionsPadLength = 60 - optionsLength; - } - - final byte[] data = new byte[240 + optionsLength + optionsPadLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - bb.put(this.opCode); - bb.put(this.hardwareType); - bb.put(this.hardwareAddressLength); - bb.put(this.hops); - bb.putInt(this.transactionId); - bb.putShort(this.seconds); - bb.putShort(this.flags); - bb.putInt(this.clientIPAddress); - bb.putInt(this.yourIPAddress); - bb.putInt(this.serverIPAddress); - bb.putInt(this.gatewayIPAddress); - checkArgument(this.clientHardwareAddress.length <= 16, - "Hardware address is too long (%s bytes)", this.clientHardwareAddress.length); - bb.put(this.clientHardwareAddress); - if (this.clientHardwareAddress.length < 16) { - for (int i = 0; i < 16 - this.clientHardwareAddress.length; ++i) { - bb.put((byte) 0x0); - } - } - this.writeString(this.serverName, bb, 64); - this.writeString(this.bootFileName, bb, 128); - // magic cookie - bb.put((byte) 0x63); - bb.put((byte) 0x82); - bb.put((byte) 0x53); - bb.put((byte) 0x63); - for (final DHCPOption option : this.options) { - final int code = option.getCode() & 0xff; - bb.put((byte) code); - if (code != 0 && code != 255) { - bb.put(option.getLength()); - bb.put(option.getData()); - } - } - // assume the rest is padded out with zeroes - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - if (bb.remaining() < DHCP.MIN_HEADER_LENGTH) { - return this; - } - - this.opCode = bb.get(); - this.hardwareType = bb.get(); - this.hardwareAddressLength = bb.get(); - this.hops = bb.get(); - this.transactionId = bb.getInt(); - this.seconds = bb.getShort(); - this.flags = bb.getShort(); - this.clientIPAddress = bb.getInt(); - this.yourIPAddress = bb.getInt(); - this.serverIPAddress = bb.getInt(); - this.gatewayIPAddress = bb.getInt(); - final int hardwareAddressLength = 0xff & this.hardwareAddressLength; - this.clientHardwareAddress = new byte[hardwareAddressLength]; - - bb.get(this.clientHardwareAddress); - for (int i = hardwareAddressLength; i < 16; ++i) { - bb.get(); - } - this.serverName = this.readString(bb, 64); - this.bootFileName = this.readString(bb, 128); - // read the magic cookie - // magic cookie - bb.get(); - bb.get(); - bb.get(); - bb.get(); - // read options - while (bb.hasRemaining()) { - final DHCPOption option = new DHCPOption(); - int code = 0xff & bb.get(); // convert signed byte to int in range - // [0,255] - option.setCode((byte) code); - if (code == 0) { - // skip these - continue; - } else if (code != 255) { - if (bb.hasRemaining()) { - final int l = 0xff & bb.get(); // convert signed byte to - // int in range [0,255] - option.setLength((byte) l); - if (bb.remaining() >= l) { - final byte[] optionData = new byte[l]; - bb.get(optionData); - option.setData(optionData); - } else { - // Skip the invalid option and set the END option - code = 0xff; - option.setCode((byte) code); - option.setLength((byte) 0); - } - } else { - // Skip the invalid option and set the END option - code = 0xff; - option.setCode((byte) code); - option.setLength((byte) 0); - } - } - this.options.add(option); - if (code == 255) { - // remaining bytes are supposed to be 0, but ignore them just in - // case - break; - } - } - - return this; - } - - protected void writeString(final String string, final ByteBuffer bb, - final int maxLength) { - if (string == null) { - for (int i = 0; i < maxLength; ++i) { - bb.put((byte) 0x0); - } - } else { - byte[] bytes = null; - try { - bytes = string.getBytes("ascii"); - } catch (final UnsupportedEncodingException e) { - throw new RuntimeException("Failure encoding server name", e); - } - int writeLength = bytes.length; - if (writeLength > maxLength) { - writeLength = maxLength; - } - bb.put(bytes, 0, writeLength); - for (int i = writeLength; i < maxLength; ++i) { - bb.put((byte) 0x0); - } - } - } - - private static String readString(final ByteBuffer bb, final int maxLength) { - final byte[] bytes = new byte[maxLength]; - bb.get(bytes); - String result = null; - try { - result = new String(bytes, "ascii").trim(); - } catch (final UnsupportedEncodingException e) { - throw new RuntimeException("Failure decoding string", e); - } - return result; - } - - /** - * Deserializer function for DHCP packets. - * - * @return deserializer function - */ - public static Deserializer<DHCP> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, MIN_HEADER_LENGTH); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - DHCP dhcp = new DHCP(); - - dhcp.opCode = bb.get(); - dhcp.hardwareType = bb.get(); - dhcp.hardwareAddressLength = bb.get(); - dhcp.hops = bb.get(); - dhcp.transactionId = bb.getInt(); - dhcp.seconds = bb.getShort(); - dhcp.flags = bb.getShort(); - dhcp.clientIPAddress = bb.getInt(); - dhcp.yourIPAddress = bb.getInt(); - dhcp.serverIPAddress = bb.getInt(); - dhcp.gatewayIPAddress = bb.getInt(); - final int hardwareAddressLength = 0xff & dhcp.hardwareAddressLength; - dhcp.clientHardwareAddress = new byte[hardwareAddressLength]; - - bb.get(dhcp.clientHardwareAddress); - for (int i = hardwareAddressLength; i < 16; ++i) { - bb.get(); - } - dhcp.serverName = readString(bb, 64); - dhcp.bootFileName = readString(bb, 128); - // read the magic cookie - // magic cookie - bb.get(); - bb.get(); - bb.get(); - bb.get(); - - // read options - boolean foundEndOptionsMarker = false; - while (bb.hasRemaining()) { - final DHCPOption option = new DHCPOption(); - int code = 0xff & bb.get(); // convert signed byte to int in range - // [0,255] - option.setCode((byte) code); - if (code == 0) { - // skip these - continue; - } else if (code != 255) { - if (bb.hasRemaining()) { - final int l = 0xff & bb.get(); // convert signed byte to - // int in range [0,255] - option.setLength((byte) l); - if (bb.remaining() >= l) { - final byte[] optionData = new byte[l]; - bb.get(optionData); - option.setData(optionData); - dhcp.options.add(option); - } else { - throw new DeserializationException( - "Buffer underflow while reading DHCP option"); - } - } - } else if (code == 255) { - DHCPOption end = new DHCPOption(); - end.setCode((byte) 255); - dhcp.options.add(end); - // remaining bytes are supposed to be 0, but ignore them just in - // case - foundEndOptionsMarker = true; - break; - } - } - - if (!foundEndOptionsMarker) { - throw new DeserializationException("DHCP End options marker was missing"); - } - - return dhcp; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCPOption.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCPOption.java deleted file mode 100644 index 1b6c670e..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCPOption.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.util.Arrays; - -/** - * - */ -public class DHCPOption { - protected byte code; - protected byte length; - protected byte[] data; - - /** - * @return the code - */ - public byte getCode() { - return this.code; - } - - /** - * @param code - * the code to set - * @return this - */ - public DHCPOption setCode(final byte code) { - this.code = code; - return this; - } - - /** - * @return the length - */ - public byte getLength() { - return this.length; - } - - /** - * @param length - * the length to set - * @return this - */ - public DHCPOption setLength(final byte length) { - this.length = length; - return this; - } - - /** - * @return the data - */ - public byte[] getData() { - return this.data; - } - - /** - * @param data - * the data to set - * @return this - */ - public DHCPOption setData(final byte[] data) { - this.data = data; - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + this.code; - result = prime * result + Arrays.hashCode(this.data); - result = prime * result + this.length; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof DHCPOption)) { - return false; - } - final DHCPOption other = (DHCPOption) obj; - if (this.code != other.code) { - return false; - } - if (!Arrays.equals(this.data, other.data)) { - return false; - } - if (this.length != other.length) { - return false; - } - return true; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return "DHCPOption [code=" + this.code + ", length=" + this.length - + ", data=" + Arrays.toString(this.data) + "]"; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCPPacketType.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCPPacketType.java deleted file mode 100644 index 8254c770..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DHCPPacketType.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -public enum DHCPPacketType { - // From RFC 1533 - DHCPDISCOVER(1), DHCPOFFER(2), DHCPREQUEST(3), DHCPDECLINE(4), DHCPACK(5), DHCPNAK( - 6), DHCPRELEASE(7), - - // From RFC2132 - DHCPINFORM(8), - - // From RFC3203 - DHCPFORCERENEW(9), - - // From RFC4388 - DHCPLEASEQUERY(10), DHCPLEASEUNASSIGNED(11), DHCPLEASEUNKNOWN(12), DHCPLEASEACTIVE( - 13); - - protected int value; - - private DHCPPacketType(final int value) { - this.value = value; - } - - public int getValue() { - return this.value; - } - - @Override - public String toString() { - switch (this.value) { - case 1: - return "DHCPDISCOVER"; - case 2: - return "DHCPOFFER"; - case 3: - return "DHCPREQUEST"; - case 4: - return "DHCPDECLINE"; - case 5: - return "DHCPACK"; - case 6: - return "DHCPNAK"; - case 7: - return "DHCPRELEASE"; - case 8: - return "DHCPINFORM"; - case 9: - return "DHCPFORCERENEW"; - case 10: - return "DHCPLEASEQUERY"; - case 11: - return "DHCPLEASEUNASSIGNED"; - case 12: - return "DHCPLEASEUNKNOWN"; - case 13: - return "DHCPLEASEACTIVE"; - default: - break; - } - - return null; - } - - public static DHCPPacketType getType(final int value) { - switch (value) { - case 1: - return DHCPDISCOVER; - case 2: - return DHCPOFFER; - case 3: - return DHCPREQUEST; - case 4: - return DHCPDECLINE; - case 5: - return DHCPACK; - case 6: - return DHCPNAK; - case 7: - return DHCPRELEASE; - case 8: - return DHCPINFORM; - case 9: - return DHCPFORCERENEW; - case 10: - return DHCPLEASEQUERY; - case 11: - return DHCPLEASEUNASSIGNED; - case 12: - return DHCPLEASEUNKNOWN; - case 13: - return DHCPLEASEACTIVE; - default: - break; - } - - return null; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Data.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Data.java deleted file mode 100644 index 79abcba1..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Data.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.util.Arrays; - -import static org.onlab.packet.PacketUtils.*; - -/** - * - */ -public class Data extends BasePacket { - protected byte[] data; - - /** - * - */ - public Data() { - data = new byte[0]; - } - - /** - * @param data the data - */ - public Data(final byte[] data) { - this.data = data; - } - - /** - * @return the data - */ - public byte[] getData() { - return this.data; - } - - /** - * @param data - * the data to set - * @return self - */ - public Data setData(final byte[] data) { - this.data = data; - return this; - } - - @Override - public byte[] serialize() { - return this.data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - this.data = Arrays.copyOfRange(data, offset, data.length); - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 1571; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(this.data); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof Data)) { - return false; - } - final Data other = (Data) obj; - if (!Arrays.equals(this.data, other.data)) { - return false; - } - return true; - } - - /** - * Deserializer function for generic payload data. - * - * @return deserializer function - */ - public static Deserializer<Data> deserializer() { - return (data, offset, length) -> { - // Allow zero-length data for now - if (length == 0) { - return new Data(); - } - - checkInput(data, offset, length, 1); - - Data dataObject = new Data(); - - dataObject.data = Arrays.copyOfRange(data, offset, data.length); - - return dataObject; - }; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DeserializationException.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DeserializationException.java deleted file mode 100644 index 03a8aa35..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/DeserializationException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * Signals that an error occurred during deserialization of a packet. - */ -public class DeserializationException extends Exception { - - /** - * Creates a new deserialization exception with the given message. - * - * @param message exception message - */ - public DeserializationException(String message) { - super(message); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Deserializer.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Deserializer.java deleted file mode 100644 index e0ef381b..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Deserializer.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * Function to deserialize a packet from a byte-based input stream. - */ -@FunctionalInterface -public interface Deserializer<U extends IPacket> { - - /** - * Deserialize a packet object from a byte array. - * - * @param data input array to take packet bytes from - * @param offset index where this packet header begins in the byte array - * @param length length of the packet header - * @return a deserialized packet object - * @throws DeserializationException if the packet cannot be deserialized - * from the input - */ - U deserialize(byte[] data, int offset, int length) throws DeserializationException; -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EAP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EAP.java deleted file mode 100644 index 516938a4..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EAP.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * - * * Copyright 2015 AT&T Foundry - * * - * * 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.onlab.packet; - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.checkHeaderLength; -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * EAP (Extensible Authentication Protocol) packet. - */ -public class EAP extends BasePacket { - private static final int HEADER_LENGTH = 4; - - public static final short MIN_LEN = 0x4; - public static final short EAP_HDR_LEN_REQ_RESP = 5; - public static final short EAP_HDR_LEN_SUC_FAIL = 4; - - // EAP Code - public static final byte REQUEST = 0x1; - public static final byte RESPONSE = 0x2; - public static final byte SUCCESS = 0x3; - public static final byte FAILURE = 0x4; - - // EAP Attribute Type - public static final byte ATTR_IDENTITY = 0x1; - public static final byte ATTR_NOTIFICATION = 0x2; - public static final byte ATTR_NAK = 0x3; - public static final byte ATTR_MD5 = 0x4; - public static final byte ATTR_OTP = 0x5; - public static final byte ATTR_GTC = 0x6; - public static final byte ATTR_TLS = 0xd; - - protected byte code; - protected byte identifier; - protected short length; - protected byte type; - protected byte[] data; - - - /** - * Gets the EAP code. - * - * @return EAP code - */ - public byte getCode() { - return this.code; - } - - - /** - * Sets the EAP code. - * - * @param code EAP code - * @return this - */ - public EAP setCode(final byte code) { - this.code = code; - return this; - } - - /** - * Gets the EAP identifier. - * - * @return EAP identifier - */ - public byte getIdentifier() { - return this.identifier; - } - - /** - * Sets the EAP identifier. - * - * @param identifier EAP identifier - * @return this - */ - public EAP setIdentifier(final byte identifier) { - this.identifier = identifier; - return this; - } - - /** - * Gets the get packet length. - * - * @return packet length - */ - public short getLength() { - return this.length; - } - - /** - * Sets the packet length. - * - * @param length packet length - * @return this - */ - public EAP setLength(final short length) { - this.length = length; - return this; - } - - /** - * Gets the data type. - * - * @return data type - */ - public byte getDataType() { - return this.type; - } - - /** - * Sets the data type. - * - * @param type data type - * @return this - */ - public EAP setDataType(final byte type) { - this.type = type; - return this; - } - - /** - * Gets the EAP data. - * - * @return EAP data - */ - public byte[] getData() { - return this.data; - } - - /** - * Sets the EAP data. - * - * @param data EAP data to be set - * @return this - */ - public EAP setData(final byte[] data) { - this.data = data; - return this; - } - - /** - * Default EAP constructor that sets the EAP code to 0. - */ - public EAP() { - this.code = 0; - } - - /** - * EAP constructor that initially sets all fields. - * - * @param code EAP code - * @param identifier EAP identifier - * @param type packet type - * @param data EAP data - */ - public EAP(byte code, byte identifier, byte type, byte[] data) { - this.code = code; - this.identifier = identifier; - if (this.code == REQUEST || this.code == RESPONSE) { - this.length = (short) (5 + (data == null ? 0 : data.length)); - this.type = type; - } else { - this.length = (short) (4 + (data == null ? 0 : data.length)); - } - this.data = data; - } - - /** - * Deserializer for EAP packets. - * - * @return deserializer - */ - public static Deserializer<EAP> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - EAP eap = new EAP(); - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - eap.code = bb.get(); - eap.identifier = bb.get(); - eap.length = bb.getShort(); - - checkHeaderLength(length, eap.length); - - int dataLength; - if (eap.code == REQUEST || eap.code == RESPONSE) { - eap.type = bb.get(); - dataLength = eap.length - 5; - } else { - dataLength = eap.length - 4; - } - - eap.data = new byte[dataLength]; - bb.get(eap.data); - return eap; - }; - } - - @Override - public byte[] serialize() { - final byte[] data = new byte[this.length]; - - final ByteBuffer bb = ByteBuffer.wrap(data); - bb.put(this.code); - bb.put(this.identifier); - bb.putShort(this.length); - if (this.code == REQUEST || this.code == RESPONSE) { - bb.put(this.type); - } - if (this.data != null) { - bb.put(this.data); - } - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.code = bb.get(); - this.identifier = bb.get(); - this.length = bb.getShort(); - - int dataLength; - if (this.code == REQUEST || this.code == RESPONSE) { - this.type = bb.get(); - dataLength = this.length - 5; - } else { - dataLength = this.length - 4; - } - this.data = new byte[dataLength]; - bb.get(this.data); - return this; - } - - @Override - public int hashCode() { - final int prime = 3889; - int result = super.hashCode(); - result = prime * result + this.code; - result = prime * result + this.identifier; - result = prime * result + this.length; - result = prime * result + this.type; - return result; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EAPOL.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EAPOL.java deleted file mode 100644 index 1820cc31..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EAPOL.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * - * * Copyright 2015 AT&T Foundry - * * - * * 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.onlab.packet; - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.checkHeaderLength; -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * EAPOL (Extensible Authentication Protocol over LAN) header. - */ -public class EAPOL extends BasePacket { - - private byte version = 0x01; - private byte eapolType; - private short packetLength; - - private static final int HEADER_LENGTH = 4; - - // EAPOL Packet Type - public static final byte EAPOL_PACKET = 0x0; - public static final byte EAPOL_START = 0x1; - public static final byte EAPOL_LOGOFF = 0x2; - public static final byte EAPOL_KEY = 0x3; - public static final byte EAPOL_ASF = 0x4; - - public static final MacAddress PAE_GROUP_ADDR = MacAddress.valueOf(new byte[] { - (byte) 0x01, (byte) 0x80, (byte) 0xc2, (byte) 0x00, (byte) 0x00, (byte) 0x03 - }); - - /** - * Gets the version. - * - * @return version - */ - public byte getVersion() { - return this.version; - } - - /** - * Sets the version. - * - * @param version EAPOL version - * @return this - */ - public EAPOL setVersion(final byte version) { - this.version = version; - return this; - } - - /** - * Gets the type. - * - * @return EAPOL type - */ - public byte getEapolType() { - return this.eapolType; - } - - /** - * Sets the EAPOL type. - * - * @param eapolType EAPOL type - * @return this - */ - public EAPOL setEapolType(final byte eapolType) { - this.eapolType = eapolType; - return this; - } - - /** - * Gets the packet length. - * - * @return packet length - */ - public short getPacketLength() { - return this.packetLength; - } - - /** - * Sets the packet length. - * - * @param packetLen packet length - * @return this - */ - public EAPOL setPacketLength(final short packetLen) { - this.packetLength = packetLen; - return this; - } - - /** - * Serializes the packet, based on the code/type using the payload - * to compute its length. - * - * @return this - */ - @Override - public byte[] serialize() { - byte[] payloadData = null; - - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - // prepare the buffer to hold the version (1), packet type (1), - // packet length (2) and the eap payload. - // if there is no payload, packet length is 0 - byte[] data = new byte[4 + this.packetLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - bb.put(this.version); - bb.put(this.eapolType); - bb.putShort(this.packetLength); - - // put the EAP payload - if (payloadData != null) { - bb.put(payloadData); - } - - return data; - } - - @Override - public int hashCode() { - final int prime = 3889; - int result = super.hashCode(); - result = prime * result + this.version; - result = prime * result + this.eapolType; - result = prime * result + this.packetLength; - return result; - } - - /** - * Deserializer for EAPOL packets. - * - * @return deserializer - */ - public static Deserializer<EAPOL> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - EAPOL eapol = new EAPOL(); - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - eapol.setVersion(bb.get()); - eapol.setEapolType(bb.get()); - eapol.setPacketLength(bb.getShort()); - - if (eapol.packetLength > 0) { - checkHeaderLength(length, HEADER_LENGTH + eapol.packetLength); - // deserialize the EAP Payload - eapol.payload = EAP.deserializer().deserialize(data, - bb.position(), bb.limit() - bb.position()); - - eapol.payload.setParent(eapol); - } - - return eapol; - }; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - // deserialize the EAPOL header - this.version = bb.get(); - this.eapolType = bb.get(); - this.packetLength = bb.getShort(); - - if (this.packetLength > 0) { - // deserialize the EAP Payload - this.payload = new EAP(); - - this.payload = this.payload.deserialize(data, bb.position(), length - 4); - this.payload.setParent(this); - } - - return this; - } -} - diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EthType.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EthType.java deleted file mode 100644 index b3b79e2c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/EthType.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * Representation of an Ethertype. - */ -public class EthType { - - /** - * A list of known ethertypes. Adding a fully defined enum here will - * associated the ethertype with a textual representation and a parsing - * class. - */ - public enum EtherType { - - ARP(0x806, "arp", org.onlab.packet.ARP.deserializer()), - RARP(0x8035, "rarp", org.onlab.packet.ARP.deserializer()), - IPV4(0x800, "ipv4", org.onlab.packet.IPv4.deserializer()), - IPV6(0x86dd, "ipv6", org.onlab.packet.IPv6.deserializer()), - LLDP(0x88cc, "lldp", org.onlab.packet.LLDP.deserializer()), - VLAN(0x8100, "vlan", null), - BDDP(0x8942, "bddp", org.onlab.packet.LLDP.deserializer()), - MPLS_UNICAST(0x8847, "mpls_unicast", org.onlab.packet.MPLS.deserializer()), - MPLS_MULTICAST(0x8848, "mpls_unicast", org.onlab.packet.MPLS.deserializer()), - EAPOL(0x888e, "eapol", org.onlab.packet.EAPOL.deserializer()), - UNKNOWN(0, "unknown", null); - - - private final EthType etherType; - private final String type; - private final Deserializer<?> deserializer; - - /** - * Constructs a new ethertype. - * - * @param ethType The actual ethertype - * @param type it's textual representation - * @param deserializer a parser for this ethertype - */ - EtherType(int ethType, String type, Deserializer<?> deserializer) { - this.etherType = new EthType(ethType); - this.type = type; - this.deserializer = deserializer; - } - - public EthType ethType() { - return etherType; - } - - @Override - public String toString() { - return type; - } - - public Deserializer<?> deserializer() { - return deserializer; - } - - public static EtherType lookup(short etherType) { - for (EtherType ethType : EtherType.values()) { - if (ethType.ethType().toShort() == etherType) { - return ethType; - } - } - return UNKNOWN; - } - - } - - - private final short etherType; - - /** - * Builds the EthType. - * - * @param etherType an integer representing an ethtype - */ - public EthType(int etherType) { - this.etherType = (short) (etherType & 0xFFFF); - } - - /** - * Builds the EthType. - * - * @param etherType a short representing the ethtype - */ - public EthType(short etherType) { - this.etherType = etherType; - } - - /** - * Returns the short value for this ethtype. - * - * @return a short value - */ - public short toShort() { - return etherType; - } - - /** - * Looks up the ethertype by it's numerical representation - * and returns it's textual format. - * - * @param etherType the short value of the ethertype - * @return a textual representation - */ - public EtherType lookup(short etherType) { - for (EtherType ethType : EtherType.values()) { - if (ethType.ethType().toShort() == etherType) { - return ethType; - } - } - return null; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - EthType ethType = (EthType) o; - - if (etherType != ethType.etherType) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return (int) etherType; - } - - public String toString() { - EtherType ethType = lookup(this.etherType); - return (ethType == null ? String.format("0x%04x", etherType) : - ethType.toString()); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java deleted file mode 100644 index 9ab5cab1..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ethernet.java +++ /dev/null @@ -1,718 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.onlab.packet.ndp.NeighborAdvertisement; -import org.onlab.packet.ndp.NeighborSolicitation; -import org.onlab.packet.ndp.Redirect; -import org.onlab.packet.ndp.RouterAdvertisement; -import org.onlab.packet.ndp.RouterSolicitation; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.onlab.packet.PacketUtils.checkHeaderLength; -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * - */ -public class Ethernet extends BasePacket { - private static final String HEXES = "0123456789ABCDEF"; - - public static final short TYPE_ARP = EthType.EtherType.ARP.ethType().toShort(); - public static final short TYPE_RARP = EthType.EtherType.RARP.ethType().toShort(); - public static final short TYPE_IPV4 = EthType.EtherType.IPV4.ethType().toShort(); - public static final short TYPE_IPV6 = EthType.EtherType.IPV6.ethType().toShort(); - public static final short TYPE_LLDP = EthType.EtherType.LLDP.ethType().toShort(); - public static final short TYPE_VLAN = EthType.EtherType.VLAN.ethType().toShort(); - public static final short TYPE_BSN = EthType.EtherType.BDDP.ethType().toShort(); - - public static final short MPLS_UNICAST = EthType.EtherType.MPLS_UNICAST.ethType().toShort();; - public static final short MPLS_MULTICAST = EthType.EtherType.MPLS_MULTICAST.ethType().toShort(); - - - public static final short VLAN_UNTAGGED = (short) 0xffff; - - public static final short ETHERNET_HEADER_LENGTH = 14; // bytes - public static final short VLAN_HEADER_LENGTH = 4; // bytes - - public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes - - private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP = - new HashMap<>(); - - static { - for (EthType.EtherType ethType : EthType.EtherType.values()) { - if (ethType.deserializer() != null) { - ETHERTYPE_DESERIALIZER_MAP.put(ethType.ethType().toShort(), ethType.deserializer()); - } - } - } - - protected MacAddress destinationMACAddress; - protected MacAddress sourceMACAddress; - protected byte priorityCode; - protected short vlanID; - protected short etherType; - protected boolean pad = false; - - /** - * By default, set Ethernet to untagged. - */ - public Ethernet() { - super(); - this.vlanID = Ethernet.VLAN_UNTAGGED; - } - - /** - * Gets the destination MAC address. - * - * @return the destination MAC as a byte array - */ - public byte[] getDestinationMACAddress() { - return this.destinationMACAddress.toBytes(); - } - - /** - * Gets the destination MAC address. - * - * @return the destination MAC - */ - public MacAddress getDestinationMAC() { - return this.destinationMACAddress; - } - - /** - * Sets the destination MAC address. - * - * @param destMac the destination MAC to set - * @return the Ethernet frame - */ - public Ethernet setDestinationMACAddress(final MacAddress destMac) { - this.destinationMACAddress = checkNotNull(destMac); - return this; - } - - /** - * Sets the destination MAC address. - * - * @param destMac the destination MAC to set - * @return the Ethernet frame - */ - public Ethernet setDestinationMACAddress(final byte[] destMac) { - this.destinationMACAddress = MacAddress.valueOf(destMac); - return this; - } - - /** - * Sets the destination MAC address. - * - * @param destMac the destination MAC to set - * @return the Ethernet frame - */ - public Ethernet setDestinationMACAddress(final String destMac) { - this.destinationMACAddress = MacAddress.valueOf(destMac); - return this; - } - - /** - * Gets the source MAC address. - * - * @return the source MACAddress as a byte array - */ - public byte[] getSourceMACAddress() { - return this.sourceMACAddress.toBytes(); - } - - /** - * Gets the source MAC address. - * - * @return the source MACAddress - */ - public MacAddress getSourceMAC() { - return this.sourceMACAddress; - } - - /** - * Sets the source MAC address. - * - * @param sourceMac the source MAC to set - * @return the Ethernet frame - */ - public Ethernet setSourceMACAddress(final MacAddress sourceMac) { - this.sourceMACAddress = checkNotNull(sourceMac); - return this; - } - - /** - * Sets the source MAC address. - * - * @param sourceMac the source MAC to set - * @return the Ethernet frame - */ - public Ethernet setSourceMACAddress(final byte[] sourceMac) { - this.sourceMACAddress = MacAddress.valueOf(sourceMac); - return this; - } - - /** - * Sets the source MAC address. - * - * @param sourceMac the source MAC to set - * @return the Ethernet frame - */ - public Ethernet setSourceMACAddress(final String sourceMac) { - this.sourceMACAddress = MacAddress.valueOf(sourceMac); - return this; - } - - /** - * Gets the priority code. - * - * @return the priorityCode - */ - public byte getPriorityCode() { - return this.priorityCode; - } - - /** - * Sets the priority code. - * - * @param priority the priorityCode to set - * @return the Ethernet frame - */ - public Ethernet setPriorityCode(final byte priority) { - this.priorityCode = priority; - return this; - } - - /** - * Gets the VLAN ID. - * - * @return the vlanID - */ - public short getVlanID() { - return this.vlanID; - } - - /** - * Sets the VLAN ID. - * - * @param vlan the vlanID to set - * @return the Ethernet frame - */ - public Ethernet setVlanID(final short vlan) { - this.vlanID = vlan; - return this; - } - - /** - * Gets the Ethernet type. - * - * @return the etherType - */ - public short getEtherType() { - return this.etherType; - } - - /** - * Sets the Ethernet type. - * - * @param ethType the etherType to set - * @return the Ethernet frame - */ - public Ethernet setEtherType(final short ethType) { - this.etherType = ethType; - return this; - } - - /** - * @return True if the Ethernet frame is broadcast, false otherwise - */ - public boolean isBroadcast() { - assert this.destinationMACAddress.length() == 6; - return this.destinationMACAddress.isBroadcast(); - } - - /** - * @return True is the Ethernet frame is multicast, False otherwise - */ - public boolean isMulticast() { - return this.destinationMACAddress.isMulticast(); - } - - /** - * Pad this packet to 60 bytes minimum, filling with zeros? - * - * @return the pad - */ - public boolean isPad() { - return this.pad; - } - - /** - * Pad this packet to 60 bytes minimum, filling with zeros? - * - * @param pd - * the pad to set - * @return this - */ - public Ethernet setPad(final boolean pd) { - this.pad = pd; - return this; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - int length = 14 + (this.vlanID == Ethernet.VLAN_UNTAGGED ? 0 : 4) - + (payloadData == null ? 0 : payloadData.length); - if (this.pad && length < 60) { - length = 60; - } - final byte[] data = new byte[length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - bb.put(this.destinationMACAddress.toBytes()); - bb.put(this.sourceMACAddress.toBytes()); - if (this.vlanID != Ethernet.VLAN_UNTAGGED) { - bb.putShort(TYPE_VLAN); - bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff)); - } - bb.putShort(this.etherType); - if (payloadData != null) { - bb.put(payloadData); - } - if (this.pad) { - Arrays.fill(data, bb.position(), data.length, (byte) 0x0); - } - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - if (length <= 0) { - return null; - } - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - if (this.destinationMACAddress == null) { - this.destinationMACAddress = MacAddress.valueOf(new byte[6]); - } - final byte[] dstAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH]; - bb.get(dstAddr); - this.destinationMACAddress = MacAddress.valueOf(dstAddr); - - if (this.sourceMACAddress == null) { - this.sourceMACAddress = MacAddress.valueOf(new byte[6]); - } - final byte[] srcAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH]; - bb.get(srcAddr); - this.sourceMACAddress = MacAddress.valueOf(srcAddr); - - short ethType = bb.getShort(); - if (ethType == TYPE_VLAN) { - final short tci = bb.getShort(); - this.priorityCode = (byte) (tci >> 13 & 0x07); - this.vlanID = (short) (tci & 0x0fff); - ethType = bb.getShort(); - } else { - this.vlanID = Ethernet.VLAN_UNTAGGED; - } - this.etherType = ethType; - - IPacket payload; - Deserializer<? extends IPacket> deserializer; - if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) { - deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType); - } else { - deserializer = Data.deserializer(); - } - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - return this; - } - - /** - * Checks to see if a string is a valid MAC address. - * - * @param macAddress string to test if it is a valid MAC - * @return True if macAddress is a valid MAC, False otherwise - */ - public static boolean isMACAddress(final String macAddress) { - final String[] macBytes = macAddress.split(":"); - if (macBytes.length != 6) { - return false; - } - for (int i = 0; i < 6; ++i) { - if (Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1 - || Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt( - 1)) == -1) { - return false; - } - } - return true; - } - - /** - * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not - * matter, and returns a corresponding byte[]. - * - * @param macAddress - * The MAC address to convert into a byte array - * @return The macAddress as a byte array - */ - public static byte[] toMACAddress(final String macAddress) { - return MacAddress.valueOf(macAddress).toBytes(); - } - - /** - * Accepts a MAC address and returns the corresponding long, where the MAC - * bytes are set on the lower order bytes of the long. - * - * @param macAddress MAC address as a byte array - * @return a long containing the mac address bytes - */ - public static long toLong(final byte[] macAddress) { - return MacAddress.valueOf(macAddress).toLong(); - } - - /** - * Converts a long MAC address to a byte array. - * - * @param macAddress MAC address set on the lower order bytes of the long - * @return the bytes of the mac address - */ - public static byte[] toByteArray(final long macAddress) { - return MacAddress.valueOf(macAddress).toBytes(); - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 7867; - int result = super.hashCode(); - result = prime * result + this.destinationMACAddress.hashCode(); - result = prime * result + this.etherType; - result = prime * result + this.vlanID; - result = prime * result + this.priorityCode; - result = prime * result + (this.pad ? 1231 : 1237); - result = prime * result + this.sourceMACAddress.hashCode(); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof Ethernet)) { - return false; - } - final Ethernet other = (Ethernet) obj; - if (!this.destinationMACAddress.equals(other.destinationMACAddress)) { - return false; - } - if (this.priorityCode != other.priorityCode) { - return false; - } - if (this.vlanID != other.vlanID) { - return false; - } - if (this.etherType != other.etherType) { - return false; - } - if (this.pad != other.pad) { - return false; - } - if (!this.sourceMACAddress.equals(other.sourceMACAddress)) { - return false; - } - return true; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString(java.lang.Object) - */ - @Override - public String toString() { - - final StringBuffer sb = new StringBuffer("\n"); - - final IPacket pkt = this.getPayload(); - - if (pkt instanceof ARP) { - sb.append("arp"); - } else if (pkt instanceof LLDP) { - sb.append("lldp"); - } else if (pkt instanceof ICMP) { - sb.append("icmp"); - } else if (pkt instanceof IPv4) { - sb.append("ip"); - } else if (pkt instanceof DHCP) { - sb.append("dhcp"); - } else { - sb.append(this.getEtherType()); - } - - sb.append("\ndl_vlan: "); - if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) { - sb.append("untagged"); - } else { - sb.append(this.getVlanID()); - } - sb.append("\ndl_vlan_pcp: "); - sb.append(this.getPriorityCode()); - sb.append("\ndl_src: "); - sb.append(bytesToHex(this.getSourceMACAddress())); - sb.append("\ndl_dst: "); - sb.append(bytesToHex(this.getDestinationMACAddress())); - - if (pkt instanceof ARP) { - final ARP p = (ARP) pkt; - sb.append("\nnw_src: "); - sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p - .getSenderProtocolAddress()))); - sb.append("\nnw_dst: "); - sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p - .getTargetProtocolAddress()))); - } else if (pkt instanceof LLDP) { - sb.append("lldp packet"); - } else if (pkt instanceof ICMP) { - final ICMP icmp = (ICMP) pkt; - sb.append("\nicmp_type: "); - sb.append(icmp.getIcmpType()); - sb.append("\nicmp_code: "); - sb.append(icmp.getIcmpCode()); - } else if (pkt instanceof IPv4) { - final IPv4 p = (IPv4) pkt; - sb.append("\nnw_src: "); - sb.append(IPv4.fromIPv4Address(p.getSourceAddress())); - sb.append("\nnw_dst: "); - sb.append(IPv4.fromIPv4Address(p.getDestinationAddress())); - sb.append("\nnw_tos: "); - sb.append(p.getDiffServ()); - sb.append("\nnw_proto: "); - sb.append(p.getProtocol()); - - IPacket payload = pkt.getPayload(); - if (payload != null) { - if (payload instanceof TCP) { - sb.append("\ntp_src: "); - sb.append(((TCP) payload).getSourcePort()); - sb.append("\ntp_dst: "); - sb.append(((TCP) payload).getDestinationPort()); - - } else if (payload instanceof UDP) { - sb.append("\ntp_src: "); - sb.append(((UDP) payload).getSourcePort()); - sb.append("\ntp_dst: "); - sb.append(((UDP) payload).getDestinationPort()); - } else if (payload instanceof ICMP) { - final ICMP icmp = (ICMP) payload; - sb.append("\nicmp_type: "); - sb.append(icmp.getIcmpType()); - sb.append("\nicmp_code: "); - sb.append(icmp.getIcmpCode()); - } - } - } else if (pkt instanceof IPv6) { - final IPv6 ipv6 = (IPv6) pkt; - sb.append("\nipv6_src: "); - sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString()); - sb.append("\nipv6_dst: "); - sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString()); - sb.append("\nipv6_proto: "); - sb.append(ipv6.getNextHeader()); - - IPacket payload = pkt.getPayload(); - if (payload != null && payload instanceof ICMP6) { - final ICMP6 icmp6 = (ICMP6) payload; - sb.append("\nicmp6_type: "); - sb.append(icmp6.getIcmpType()); - sb.append("\nicmp6_code: "); - sb.append(icmp6.getIcmpCode()); - - payload = payload.getPayload(); - if (payload != null) { - if (payload instanceof NeighborSolicitation) { - final NeighborSolicitation ns = (NeighborSolicitation) payload; - sb.append("\nns_target_addr: "); - sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString()); - ns.getOptions().forEach(option -> { - sb.append("\noption_type: "); - sb.append(option.type()); - sb.append("\noption_data: "); - sb.append(bytesToHex(option.data())); - }); - } else if (payload instanceof NeighborAdvertisement) { - final NeighborAdvertisement na = (NeighborAdvertisement) payload; - sb.append("\nna_target_addr: "); - sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString()); - sb.append("\nna_solicited_flag: "); - sb.append(na.getSolicitedFlag()); - sb.append("\nna_router_flag: "); - sb.append(na.getRouterFlag()); - sb.append("\nna_override_flag: "); - sb.append(na.getOverrideFlag()); - na.getOptions().forEach(option -> { - sb.append("\noption_type: "); - sb.append(option.type()); - sb.append("\noption_data: "); - sb.append(bytesToHex(option.data())); - }); - } else if (payload instanceof RouterSolicitation) { - final RouterSolicitation rs = (RouterSolicitation) payload; - sb.append("\nrs"); - rs.getOptions().forEach(option -> { - sb.append("\noption_type: "); - sb.append(option.type()); - sb.append("\noption_data: "); - sb.append(bytesToHex(option.data())); - }); - } else if (payload instanceof RouterAdvertisement) { - final RouterAdvertisement ra = (RouterAdvertisement) payload; - sb.append("\nra_hop_limit: "); - sb.append(ra.getCurrentHopLimit()); - sb.append("\nra_mflag: "); - sb.append(ra.getMFlag()); - sb.append("\nra_oflag: "); - sb.append(ra.getOFlag()); - sb.append("\nra_reachable_time: "); - sb.append(ra.getReachableTime()); - sb.append("\nra_retransmit_time: "); - sb.append(ra.getRetransmitTimer()); - sb.append("\nra_router_lifetime: "); - sb.append(ra.getRouterLifetime()); - ra.getOptions().forEach(option -> { - sb.append("\noption_type: "); - sb.append(option.type()); - sb.append("\noption_data: "); - sb.append(bytesToHex(option.data())); - }); - } else if (payload instanceof Redirect) { - final Redirect rd = (Redirect) payload; - sb.append("\nrd_target_addr: "); - sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString()); - rd.getOptions().forEach(option -> { - sb.append("\noption_type: "); - sb.append(option.type()); - sb.append("\noption_data: "); - sb.append(bytesToHex(option.data())); - }); - } - } - } - } else if (pkt instanceof DHCP) { - sb.append("\ndhcp packet"); - } else if (pkt instanceof Data) { - sb.append("\ndata packet"); - } else if (pkt instanceof LLC) { - sb.append("\nllc packet"); - } else { - sb.append("\nunknown packet"); - } - - return sb.toString(); - } - - public static String bytesToHex(byte[] in) { - final StringBuilder builder = new StringBuilder(); - for (byte b : in) { - builder.append(String.format("%02x", b)); - } - return builder.toString(); - } - - /** - * Deserializer function for Ethernet packets. - * - * @return deserializer function - */ - public static Deserializer<Ethernet> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, ETHERNET_HEADER_LENGTH); - - byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH]; - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - Ethernet eth = new Ethernet(); - // Read destination MAC address into buffer - bb.get(addressBuffer); - eth.setDestinationMACAddress(addressBuffer); - - // Read source MAC address into buffer - bb.get(addressBuffer); - eth.setSourceMACAddress(addressBuffer); - - short ethType = bb.getShort(); - if (ethType == TYPE_VLAN) { - checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH); - final short tci = bb.getShort(); - eth.setPriorityCode((byte) (tci >> 13 & 0x07)); - eth.setVlanID((short) (tci & 0x0fff)); - ethType = bb.getShort(); - } else { - eth.setVlanID(Ethernet.VLAN_UNTAGGED); - } - eth.setEtherType(ethType); - - IPacket payload; - Deserializer<? extends IPacket> deserializer; - if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) { - deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType); - } else { - deserializer = Data.deserializer(); - } - payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - payload.setParent(eth); - eth.setPayload(payload); - - return eth; - }; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ICMP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ICMP.java deleted file mode 100644 index d07a9ba4..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ICMP.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.*; - -/** - * Implements ICMP packet format. - * - */ -public class ICMP extends BasePacket { - protected byte icmpType; - protected byte icmpCode; - protected short checksum; - - public static final byte TYPE_ECHO_REQUEST = 0x08; - public static final byte TYPE_ECHO_REPLY = 0x00; - public static final byte SUBTYPE_ECHO_REPLY = 0x00; - - public static final short ICMP_HEADER_LENGTH = 4; - - /** - * @return the icmpType - */ - public byte getIcmpType() { - return this.icmpType; - } - - /** - * @param icmpType - * to set - * @return this - */ - public ICMP setIcmpType(final byte icmpType) { - this.icmpType = icmpType; - return this; - } - - /** - * @return the icmp code - */ - public byte getIcmpCode() { - return this.icmpCode; - } - - /** - * @param icmpCode - * code to set - * @return this - */ - public ICMP setIcmpCode(final byte icmpCode) { - this.icmpCode = icmpCode; - return this; - } - - /** - * @return the checksum - */ - public short getChecksum() { - return this.checksum; - } - - /** - * @param checksum - * the checksum to set - * @return this - */ - public ICMP setChecksum(final short checksum) { - this.checksum = checksum; - return this; - } - - /** - * Serializes the packet. Will compute and set the following fields if they - * are set to specific values at the time serialize is called: -checksum : 0 - * -length : 0 - */ - @Override - public byte[] serialize() { - int length = 4; - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - length += payloadData.length; - } - - final byte[] data = new byte[length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.icmpType); - bb.put(this.icmpCode); - bb.putShort(this.checksum); - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof IPv4) { - ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_ICMP); - } - - // compute checksum if needed - if (this.checksum == 0) { - bb.rewind(); - int accumulation = 0; - - for (int i = 0; i < length / 2; ++i) { - accumulation += 0xffff & bb.getShort(); - } - // pad to an even number of shorts - if (length % 2 > 0) { - accumulation += (bb.get() & 0xff) << 8; - } - - accumulation = (accumulation >> 16 & 0xffff) - + (accumulation & 0xffff); - this.checksum = (short) (~accumulation & 0xffff); - bb.putShort(2, this.checksum); - } - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.icmpType = bb.get(); - this.icmpCode = bb.get(); - this.checksum = bb.getShort(); - - this.payload = new Data(); - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() - - bb.position()); - this.payload.setParent(this); - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.icmpType; - result = prime * result + this.icmpCode; - result = prime * result + this.checksum; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof ICMP)) { - return false; - } - final ICMP other = (ICMP) obj; - if (this.icmpType != other.icmpType) { - return false; - } - if (this.icmpCode != other.icmpCode) { - return false; - } - if (this.checksum != other.checksum) { - return false; - } - return true; - } - - /** - * Deserializer function for ICMP packets. - * - * @return deserializer function - */ - public static Deserializer<ICMP> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, ICMP_HEADER_LENGTH); - - ICMP icmp = new ICMP(); - - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - icmp.icmpType = bb.get(); - icmp.icmpCode = bb.get(); - icmp.checksum = bb.getShort(); - - icmp.payload = Data.deserializer() - .deserialize(data, bb.position(), bb.limit() - - bb.position()); - icmp.payload.setParent(icmp); - return icmp; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ICMP6.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ICMP6.java deleted file mode 100644 index c8981302..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ICMP6.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.onlab.packet.ipv6.IExtensionHeader; -import org.onlab.packet.ndp.NeighborAdvertisement; -import org.onlab.packet.ndp.NeighborSolicitation; -import org.onlab.packet.ndp.Redirect; -import org.onlab.packet.ndp.RouterAdvertisement; -import org.onlab.packet.ndp.RouterSolicitation; - -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements ICMPv6 packet format. (RFC 4443) - */ -public class ICMP6 extends BasePacket { - public static final byte HEADER_LENGTH = 4; // bytes - - // Type - /** Destination Unreachable. */ - public static final byte DEST_UNREACH = (byte) 0x01; - /** Packet Too Big. */ - public static final byte PKT_TOO_BIG = (byte) 0x02; - /** Time Exceeded. */ - public static final byte TIME_EXCEED = (byte) 0x03; - /** Parameter Problem. */ - public static final byte PARAM_ERR = (byte) 0x04; - /** Echo Request. */ - public static final byte ECHO_REQUEST = (byte) 0x80; - /** Echo Reply. */ - public static final byte ECHO_REPLY = (byte) 0x81; - /** Multicast Listener Query. */ - public static final byte MCAST_QUERY = (byte) 0x82; - /** Multicast Listener Report. */ - public static final byte MCAST_REPORT = (byte) 0x83; - /** Multicast Listener Done. */ - public static final byte MCAST_DONE = (byte) 0x84; - /** Router Solicitation. */ - public static final byte ROUTER_SOLICITATION = (byte) 0x85; - /** Router Advertisement. */ - public static final byte ROUTER_ADVERTISEMENT = (byte) 0x86; - /** Neighbor Solicitation. */ - public static final byte NEIGHBOR_SOLICITATION = (byte) 0x87; - /** Neighbor Advertisement. */ - public static final byte NEIGHBOR_ADVERTISEMENT = (byte) 0x88; - /** Redirect Message. */ - public static final byte REDIRECT = (byte) 0x89; - - // Code for DEST_UNREACH - /** No route to destination. */ - public static final byte NO_ROUTE = (byte) 0x00; - /** Communication with destination administratively prohibited. */ - public static final byte COMM_PROHIBIT = (byte) 0x01; - /** Beyond scope of source address. */ - public static final byte BEYOND_SCOPE = (byte) 0x02; - /** Address unreachable. */ - public static final byte ADDR_UNREACH = (byte) 0x03; - /** Port unreachable. */ - public static final byte PORT_UNREACH = (byte) 0x04; - /** Source address failed ingress/egress policy. */ - public static final byte FAIL_POLICY = (byte) 0x05; - /** Reject route to destination. */ - public static final byte REJECT_ROUTE = (byte) 0x06; - /** Error in Source Routing Header. */ - public static final byte SRC_ROUTING_HEADER_ERR = (byte) 0x07; - - // Code for TIME_EXCEED - /** Hop limit exceeded in transit. */ - public static final byte HOP_LIMIT_EXCEED = (byte) 0x00; - /** Fragment reassembly time exceeded. */ - public static final byte DEFRAG_TIME_EXCEED = (byte) 0x01; - - // Code for PARAM_ERR - /** Erroneous header field encountered. */ - public static final byte HDR_FIELD_ERR = (byte) 0x00; - /** Unrecognized Next Header type encountered. */ - public static final byte NEXT_HEADER_ERR = (byte) 0x01; - /** Unrecognized IPv6 option encountered. */ - public static final byte IPV6_OPT_ERR = (byte) 0x01; - - public static final Map<Byte, Deserializer<? extends IPacket>> TYPE_DESERIALIZER_MAP = - new HashMap<>(); - - static { - ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.ROUTER_SOLICITATION, RouterSolicitation.deserializer()); - ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.ROUTER_ADVERTISEMENT, RouterAdvertisement.deserializer()); - ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.NEIGHBOR_SOLICITATION, NeighborSolicitation.deserializer()); - ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.NEIGHBOR_ADVERTISEMENT, NeighborAdvertisement.deserializer()); - ICMP6.TYPE_DESERIALIZER_MAP.put(ICMP6.REDIRECT, Redirect.deserializer()); - } - - protected byte icmpType; - protected byte icmpCode; - protected short checksum; - - private static final byte[] ZERO_ADDRESS = new byte[Ip6Address.BYTE_LENGTH]; - - /** - * Gets ICMP6 type. - * - * @return the ICMP6 type - */ - public byte getIcmpType() { - return this.icmpType; - } - - /** - * Sets ICMP6 type. - * - * @param icmpType the ICMP type to set - * @return this - */ - public ICMP6 setIcmpType(final byte icmpType) { - this.icmpType = icmpType; - return this; - } - - /** - * Gets ICMP6 code. - * - * @return the ICMP6 code - */ - public byte getIcmpCode() { - return this.icmpCode; - } - - /** - * Sets ICMP6 code. - * - * @param icmpCode the ICMP6 code to set - * @return this - */ - public ICMP6 setIcmpCode(final byte icmpCode) { - this.icmpCode = icmpCode; - return this; - } - - /** - * Gets checksum. - * - * @return the checksum - */ - public short getChecksum() { - return this.checksum; - } - - /** - * Sets checksum. - * - * @param checksum the checksum to set - * @return this - */ - public ICMP6 setChecksum(final short checksum) { - this.checksum = checksum; - return this; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - int payloadLength = 0; - if (payloadData != null) { - payloadLength = payloadData.length; - } - - final byte[] data = new byte[HEADER_LENGTH + payloadLength]; - final ByteBuffer bbData = ByteBuffer.wrap(data); - - // Creating ByteBuffer for checksum calculation - final byte[] checksumData = - new byte[IPv6.FIXED_HEADER_LENGTH + HEADER_LENGTH + payloadLength]; - final ByteBuffer bbChecksum = ByteBuffer.wrap(checksumData); - - // - // Creating IPv6 Pseudo Header for checksum calculation according - // to RFC 4443 and RFC 2460 - // - IPv6 ipv6Parent = null; - for (IPacket p = this.parent; p != null; p = p.getParent()) { - if (p instanceof IPv6) { - ipv6Parent = (IPv6) p; - break; - } - } - if (ipv6Parent != null) { - bbChecksum.put(ipv6Parent.getSourceAddress()); - bbChecksum.put(ipv6Parent.getDestinationAddress()); - } else { - // NOTE: IPv6 source and destination addresses unknown. Use zeroes. - bbChecksum.put(ZERO_ADDRESS); - bbChecksum.put(ZERO_ADDRESS); - } - bbChecksum.putInt(HEADER_LENGTH + payloadLength); - bbChecksum.put((byte) 0); - bbChecksum.put((byte) 0); - bbChecksum.put((byte) 0); - bbChecksum.put(IPv6.PROTOCOL_ICMP6); - bbChecksum.put(this.icmpType); - bbChecksum.put(this.icmpCode); - bbChecksum.put((byte) 0); - bbChecksum.put((byte) 0); - - bbData.put(this.icmpType); - bbData.put(this.icmpCode); - bbData.putShort(this.checksum); - if (payloadData != null) { - bbData.put(payloadData); - bbChecksum.put(payloadData); - } - - if (this.parent != null) { - if (this.parent instanceof IPv6) { - ((IPv6) this.parent).setNextHeader(IPv6.PROTOCOL_ICMP6); - } else if (this.parent instanceof IExtensionHeader) { - ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_ICMP6); - } - } - - // compute checksum if needed - if (this.checksum == 0) { - bbData.rewind(); - bbChecksum.rewind(); - int accumulation = 0; - - for (int i = 0; i < checksumData.length / 2; ++i) { - accumulation += 0xffff & bbChecksum.getShort(); - } - // pad to an even number of shorts - if (checksumData.length % 2 > 0) { - accumulation += (bbChecksum.get() & 0xff) << 8; - } - - accumulation = (accumulation >> 16 & 0xffff) - + (accumulation & 0xffff); - this.checksum = (short) (~accumulation & 0xffff); - bbData.putShort(2, this.checksum); - } - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.icmpType = bb.get(); - this.icmpCode = bb.get(); - this.checksum = bb.getShort(); - - Deserializer<? extends IPacket> deserializer; - if (ICMP6.TYPE_DESERIALIZER_MAP.containsKey(icmpType)) { - deserializer = TYPE_DESERIALIZER_MAP.get(icmpType); - } else { - deserializer = Data.deserializer(); - } - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.icmpType; - result = prime * result + this.icmpCode; - result = prime * result + this.checksum; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof ICMP6)) { - return false; - } - final ICMP6 other = (ICMP6) obj; - if (this.icmpType != other.icmpType) { - return false; - } - if (this.icmpCode != other.icmpCode) { - return false; - } - if (this.checksum != other.checksum) { - return false; - } - return true; - } - - /** - * Deserializer function for ICMPv6 packets. - * - * @return deserializer function - */ - public static Deserializer<ICMP6> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - ICMP6 icmp6 = new ICMP6(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - icmp6.icmpType = bb.get(); - icmp6.icmpCode = bb.get(); - icmp6.checksum = bb.getShort(); - - Deserializer<? extends IPacket> deserializer; - if (ICMP6.TYPE_DESERIALIZER_MAP.containsKey(icmp6.icmpType)) { - deserializer = TYPE_DESERIALIZER_MAP.get(icmp6.icmpType); - } else { - deserializer = Data.deserializer(); - } - icmp6.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - icmp6.payload.setParent(icmp6); - - return icmp6; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMP.java deleted file mode 100644 index 254f1325..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMP.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.slf4j.Logger; - -import static org.slf4j.LoggerFactory.getLogger; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.onlab.packet.PacketUtils.checkInput; - - -/** - * Implements IGMP control packet format. - */ -public class IGMP extends BasePacket { - private final Logger log = getLogger(getClass()); - - public static final byte TYPE_IGMPV3_MEMBERSHIP_QUERY = 0x11; - public static final byte TYPE_IGMPV1_MEMBERSHIP_REPORT = 0x12; - public static final byte TYPE_IGMPV2_MEMBERSHIP_REPORT = 0x16; - public static final byte TYPE_IGMPV2_LEAVE_GROUP = 0x17; - public static final byte TYPE_IGMPV3_MEMBERSHIP_REPORT = 0x22; - public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = new HashMap<>(); - - public static final int MINIMUM_HEADER_LEN = 12; - - List<IGMPGroup> groups = new ArrayList<>(); - - // Fields contained in the IGMP header - private byte igmpType; - private byte resField = 0; - private short checksum = 0; - - private byte[] unsupportTypeData; - - public IGMP() { - } - - /** - * Get the IGMP message type. - * - * @return the IGMP message type - */ - public byte getIgmpType() { - return igmpType; - } - - /** - * Set the IGMP message type. - * - * @param msgType IGMP message type - */ - public void setIgmpType(byte msgType) { - igmpType = msgType; - } - - /** - * Get the checksum of this message. - * - * @return the checksum - */ - public short getChecksum() { - return checksum; - } - - /** - * get the Max Resp Code. - * - * @return The Maximum Time allowed before before sending a responding report. - */ - public byte getMaxRespField() { - return resField; - } - - /** - * Set the Max Resp Code. - * - * @param respCode the Maximum Response Code. - */ - public void setMaxRespCode(byte respCode) { - if (igmpType != IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY) { - log.debug("Requesting the max response code for an incorrect field: "); - } - this.resField = respCode; - } - - /** - * Get the list of IGMPGroups. The group objects will be either IGMPQuery or IGMPMembership - * depending on the IGMP message type. For IGMP Query, the groups list should only be - * one group. - * - * @return The list of IGMP groups. - */ - public List<IGMPGroup> getGroups() { - return groups; - } - - /** - * Add a multicast group to this IGMP message. - * - * @param group the IGMPGroup will be IGMPQuery or IGMPMembership depending on the message type. - * @return true if group was valid and added, false otherwise. - */ - public boolean addGroup(IGMPGroup group) { - checkNotNull(group); - switch (this.igmpType) { - case TYPE_IGMPV3_MEMBERSHIP_QUERY: - if (group instanceof IGMPMembership) { - return false; - } - - if (group.sources.size() > 1) { - return false; - } - break; - - case TYPE_IGMPV3_MEMBERSHIP_REPORT: - if (group instanceof IGMPMembership) { - return false; - } - break; - - default: - log.debug("Warning no IGMP message type has been set"); - } - - this.groups.add(group); - return true; - } - - /** - * Serialize this IGMP packet. This will take care - * of serializing IGMPv3 Queries and IGMPv3 Membership - * Reports. - * - * @return the serialized IGMP message - */ - @Override - public byte[] serialize() { - byte [] data = new byte[8915]; - - ByteBuffer bb = ByteBuffer.wrap(data); - bb.put(this.getIgmpType()); - - // reserved or max resp code depending on type. - bb.put(this.resField); - - // Must calculate checksum - bb.putShort((short) 0); - - switch (this.igmpType) { - - case IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT: - // reserved - bb.putShort((short) 0); - // Number of groups - bb.putShort((short) groups.size()); - // Fall through - - case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY: - - for (IGMPGroup grp : groups) { - grp.serialize(bb); - } - break; - - default: - bb.put(this.unsupportTypeData); - break; - } - - int size = bb.position(); - bb.position(0); - byte [] rdata = new byte[size]; - bb.get(rdata, 0, size); - return rdata; - } - - /** - * Deserialize an IGMP message. - * - * @param data bytes to deserialize - * @param offset offset to start deserializing from - * @param length length of the data to deserialize - * @return populated IGMP object - */ - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - - IGMP igmp = new IGMP(); - try { - igmp = IGMP.deserializer().deserialize(data, offset, length); - } catch (DeserializationException e) { - log.error(e.getStackTrace().toString()); - return this; - } - this.igmpType = igmp.igmpType; - this.resField = igmp.resField; - this.checksum = igmp.checksum; - this.groups = igmp.groups; - return this; - } - - /** - * Deserializer function for IPv4 packets. - * - * @return deserializer function - */ - public static Deserializer<IGMP> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, MINIMUM_HEADER_LEN); - - IGMP igmp = new IGMP(); - - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - igmp.igmpType = bb.get(); - igmp.resField = bb.get(); - igmp.checksum = bb.getShort(); - int len = MINIMUM_HEADER_LEN; - String msg; - - switch (igmp.igmpType) { - - case TYPE_IGMPV3_MEMBERSHIP_QUERY: - IGMPQuery qgroup = new IGMPQuery(); - qgroup.deserialize(bb); - igmp.groups.add(qgroup); - break; - - case TYPE_IGMPV3_MEMBERSHIP_REPORT: - bb.getShort(); // Ignore resvd - int ngrps = bb.getShort(); - - for (; ngrps > 0; ngrps--) { - IGMPMembership mgroup = new IGMPMembership(); - mgroup.deserialize(bb); - igmp.groups.add(mgroup); - } - break; - - /* - * NOTE: according to the IGMPv3 spec. These previous IGMP type fields - * must be supported. At this time we are going to <b>assume</b> we run - * in a modern network where all devices are IGMPv3 capable. - */ - case TYPE_IGMPV1_MEMBERSHIP_REPORT: - case TYPE_IGMPV2_MEMBERSHIP_REPORT: - case TYPE_IGMPV2_LEAVE_GROUP: - igmp.unsupportTypeData = bb.array(); // Is this the entire array? - msg = "IGMP message type: " + igmp.igmpType + " is not supported"; - igmp.log.debug(msg); - break; - - default: - msg = "IGMP message type: " + igmp.igmpType + " is not recognized"; - igmp.unsupportTypeData = bb.array(); - igmp.log.debug(msg); - break; - } - return igmp; - }; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof IGMP)) { - return false; - } - final IGMP other = (IGMP) obj; - if (this.igmpType != other.igmpType) { - return false; - } - if (this.resField != other.resField) { - return false; - } - if (this.checksum != other.checksum) { - return false; - } - if (this.groups.size() != other.groups.size()) { - return false; - } - // TODO: equals should be true regardless of order. - if (!groups.equals(other.groups)) { - return false; - } - return true; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - result = prime * result + this.igmpType; - result = prime * result + this.groups.size(); - result = prime * result + this.resField; - result = prime * result + this.checksum; - result = prime * result + this.groups.hashCode(); - return result; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPGroup.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPGroup.java deleted file mode 100644 index 70ff5563..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPGroup.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -/** - * A class to represent Groups for membership query and reports. - */ -public abstract class IGMPGroup { - - protected int auxInfo; - protected IpAddress gaddr; - protected List<IpAddress> sources = new ArrayList<>(); - - public IGMPGroup() { - } - - /** - * Initialize this object with a multicast group address and additional info. - * - * @param gaddr: the multicast group address for this message type. - * @param auxInfo: additional info potentially used by IGMPQuery - */ - public IGMPGroup(IpAddress gaddr, int auxInfo) { - this.gaddr = gaddr; - this.auxInfo = auxInfo; - } - - /** - * Get the multicast group address. - * - * @return the group address - */ - public IpAddress getGaddr() { - return this.gaddr; - } - - /** - * Get the auxillary info. - * - * @return the auxillary info - */ - public int getAuxInfo() { - return this.auxInfo; - } - - /** - * Add a unicast source address to this message. - * - * @param saddr IPv4 unicast source address - */ - public void addSource(IpAddress saddr) { - sources.add(saddr); - } - - /** - * Return the list of source addresses. - * - * @return list of source addresses - */ - public List<IpAddress> getSources() { - return sources; - } - - /** - * Deserialize an IGMPQuery or IGMPMembership message. - * - * @param bb the ByteBuffer wrapping the serialized message. The position of the - * ByteBuffer should be pointing at the head of either message type. - * @return An object populated with the respective IGMPGroup subclass - * @throws DeserializationException in case deserialization goes wrong - */ - public abstract IGMPGroup deserialize(ByteBuffer bb) throws DeserializationException; - - /** - * Serialize the IGMPGroup subclass. - * - * @param bb the ByteBuffer to write into, positioned at the next spot to be written to. - * @return The serialized message - */ - public abstract byte[] serialize(ByteBuffer bb); -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPMembership.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPMembership.java deleted file mode 100644 index 495e283c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPMembership.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import static org.onlab.packet.PacketUtils.checkBufferLength; - -public class IGMPMembership extends IGMPGroup { - - public static final byte MODE_IS_INCLUDE = 0x1; - public static final byte MODE_IS_EXCLUDE = 0x2; - public static final byte CHANGE_TO_INCLUDE_MODE = 0x3; - public static final byte CHANGE_TO_EXCLUDE_MODE = 0x4; - public static final byte ALLOW_NEW_SOURCES = 0x5; - public static final byte BLOCK_OLD_SOURCES = 0x6; - - private final int minGroupRecordLen = Ip4Address.BYTE_LENGTH + 4; - - protected byte recordType; - protected byte auxDataLength = 0; - protected byte[] auxData; - - /** - * Constructor initialized with a multicast group address. - * - * @param gaddr A multicast group address. - */ - public IGMPMembership(Ip4Address gaddr) { - super(gaddr, 0); - } - - /** - * Default constructor. - */ - public IGMPMembership() { - super(); - } - - /** - * Serialize this Membership Report. - * - * @param bb the ByteBuffer to write into, positioned at the next spot to be written to. - * @return serialized IGMP message. - */ - @Override - public byte[] serialize(ByteBuffer bb) { - - bb.put(recordType); - bb.put(auxDataLength); // reserved - bb.putShort((short) sources.size()); - bb.put(gaddr.toOctets()); - for (IpAddress ipaddr : sources) { - bb.put(ipaddr.toOctets()); - } - - if (auxDataLength > 0) { - bb.put(auxData); - } - - return bb.array(); - } - - /** - * Deserialize the IGMP Membership report packet. - * - * @param bb the ByteBuffer wrapping the serialized message. The position of the - * ByteBuffer should be pointing at the head of either message type. - * @return IGMP Group - * @throws DeserializationException if deserialization fails - */ - public IGMPGroup deserialize(ByteBuffer bb) throws DeserializationException { - - // Make sure there is enough buffer to read the header, - // including the number of sources - checkBufferLength(bb.remaining(), 0, minGroupRecordLen); - recordType = bb.get(); - auxDataLength = bb.get(); - int nsrcs = bb.getShort(); - - gaddr = Ip4Address.valueOf(bb.getInt()); - - // Make sure we have enough buffer to hold all of these sources - checkBufferLength(bb.remaining(), 0, Ip4Address.BYTE_LENGTH * nsrcs); - for (; nsrcs > 0; nsrcs--) { - Ip4Address src = Ip4Address.valueOf(bb.getInt()); - this.sources.add(src); - } - - if (auxDataLength > 0) { - auxData = new byte[auxDataLength]; - bb.get(auxData, 0, auxDataLength); - } - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals() - */ - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof IGMPMembership)) { - return false; - } - IGMPMembership other = (IGMPMembership) obj; - - if (!this.gaddr.equals(other.gaddr)) { - return false; - } - if (this.recordType != other.recordType) { - return false; - } - if (this.auxDataLength != other.auxDataLength) { - return false; - } - if (this.sources.size() != other.sources.size()) { - return false; - } - // TODO: make these tolerant of order - if (!this.sources.equals(other.sources)) { - return false; - } - - return true; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - result = prime * result + this.gaddr.hashCode(); - result = prime * result + this.recordType; - result = prime * result + this.auxDataLength; - result = prime * result + this.sources.hashCode(); - return result; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPQuery.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPQuery.java deleted file mode 100644 index bb53eba5..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IGMPQuery.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; - -public class IGMPQuery extends IGMPGroup { - - // Bits and bytes after the group address - private byte resv = 0; - private boolean sbit = false; - private byte qrv = 2; - private byte qqic = 0x7d; - - /** - * Create IGMP Query message. - * - * @param gaddr initiaze with a group address. - * @param auxInfo auxillary info. - */ - public IGMPQuery(IpAddress gaddr, int auxInfo) { - super(gaddr, auxInfo); - } - - /** - * Create IGMP Query message. - */ - public IGMPQuery() { - super(); - } - - /** - * Is the S flag set? Telling adjacent routers to suppress normal timer updates. - * - * @return true if the flag is set, false otherwise - */ - public boolean isSbit() { - return sbit; - } - - /** - * Set the S flag. Default is false. - * - * @param sbit true or false - */ - public void setSbit(boolean sbit) { - this.sbit = sbit; - } - - /** - * Get the Querier Robustness Variable. - * - * @return querier robustness value - */ - public byte getQrv() { - return qrv; - } - - /** - * Set the Querier Robustness Variable. Default is 2. - * - * @param qrv new querier robustness value - */ - public void setQrv(byte qrv) { - this.qrv = qrv; - } - - /** - * Get the reserved field. Should be zero, but ignored regardless of it's value. - * - * @return the reserved field. - */ - public byte getResv() { - return resv; - } - - /** - * Set the reserved field. Should be 0 and ignored by receivers. - * - * @param resv the reserved field. - */ - public void setResv(byte resv) { - this.resv = resv; - } - - /** - * Serialize this IGMPQuery. - * - * @param bb the ByteBuffer to write into, positioned at the next spot to be written to. - * @return the serialized message - */ - @Override - public byte[] serialize(ByteBuffer bb) { - - bb.put(gaddr.toOctets()); - byte fld = (byte) (0x7 & qrv); - bb.put(fld); - bb.put(qqic); - bb.putShort((short) sources.size()); - for (IpAddress ipaddr : sources) { - bb.put(ipaddr.toOctets()); - } - return bb.array(); - } - - /** - * Deserialize the IGMP Query group structure. - * - * @param bb ByteBuffer pointing at the IGMP Query group address - * @return the IGMP Group object - */ - public IGMPGroup deserialize(ByteBuffer bb) throws DeserializationException { - - gaddr = Ip4Address.valueOf(bb.getInt()); - byte fld = bb.get(); - - // Just ignore the reserved bits - resv = 0; - this.sbit = ((fld & 0x8) == 0x8); - qrv = (byte) (fld & 0x7); - - // QQIC field - qqic = bb.get(); - - // Get the number of sources. - short nsrcs = bb.getShort(); - - // Do a sanity check on the amount of space we have in our buffer. - int lengthNeeded = (Ip4Address.BYTE_LENGTH * nsrcs); - PacketUtils.checkHeaderLength(bb.remaining(), lengthNeeded); - - for (; nsrcs > 0; nsrcs--) { - Ip4Address ipaddr = Ip4Address.valueOf(bb.getInt()); - this.sources.add(ipaddr); - } - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals() - */ - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof IGMPQuery)) { - return false; - } - IGMPQuery other = (IGMPQuery) obj; - - if (this.sbit != other.sbit) { - return false; - } - if (this.qrv != other.qrv) { - return false; - } - if (this.qqic != other.qqic) { - return false; - } - if (this.sources.size() != other.sources.size()) { - return false; - } - - // TODO: make these tolerant of order - if (!this.sources.equals(other.sources)) { - return false; - } - - return true; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - result = prime * result + this.gaddr.hashCode(); - result = prime * result + this.qqic; - result = prime * result + this.qrv; - result = prime * result + this.sources.hashCode(); - return result; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPacket.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPacket.java deleted file mode 100644 index 64e6ac36..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPacket.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * - */ -public interface IPacket { - /** - * - * @return the payload - */ - IPacket getPayload(); - - /** - * - * @param packet new payload - * @return self - */ - IPacket setPayload(IPacket packet); - - /** - * - * @return parent packet - */ - IPacket getParent(); - - /** - * - * @param packet new parent - * @return self - */ - IPacket setParent(IPacket packet); - - /** - * Reset any checksums as needed, and call resetChecksum on all parents. - */ - void resetChecksum(); - - /** - * Sets all payloads parent packet if applicable, then serializes this - * packet and all payloads. - * - * @return a byte[] containing this packet and payloads - */ - byte[] serialize(); - - /** - * Deserializes this packet layer and all possible payloads. - * - * NOTE: This method has been deprecated and will be removed in a future - * release. It is now recommended to use the Deserializer function provided - * by the deserialize() method on each packet to deserialize them. The - * Deserializer functions are robust to malformed input. - * - * @param data bytes to deserialize - * @param offset - * offset to start deserializing from - * @param length - * length of the data to deserialize - * @return the deserialized data - * @deprecated in Cardinal Release - */ - @Deprecated - IPacket deserialize(byte[] data, int offset, int length); - - /** - * Clone this packet and its payload packet but not its parent. - * - * @return the clone - */ - Object clone(); -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPv4.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPv4.java deleted file mode 100644 index a5c5f4f1..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPv4.java +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import static org.onlab.packet.PacketUtils.*; - -/** - * - */ -public class IPv4 extends BasePacket { - public static final byte PROTOCOL_ICMP = 0x1; - public static final byte PROTOCOL_IGMP = 0x2; - public static final byte PROTOCOL_TCP = 0x6; - public static final byte PROTOCOL_UDP = 0x11; - public static final byte PROTOCOL_PIM = 0x67; - public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = - new HashMap<>(); - - static { - IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_ICMP, ICMP.deserializer()); - IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_IGMP, IGMP.deserializer()); - IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_TCP, TCP.deserializer()); - IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_UDP, UDP.deserializer()); - IPv4.PROTOCOL_DESERIALIZER_MAP.put(IPv4.PROTOCOL_PIM, PIM.deserializer()); - } - - private static final byte DSCP_MASK = 0x3f; - private static final byte DSCP_OFFSET = 2; - private static final byte ECN_MASK = 0x3; - - private static final short HEADER_LENGTH = 20; - - protected byte version; - protected byte headerLength; - protected byte diffServ; - protected short totalLength; - protected short identification; - protected byte flags; - protected short fragmentOffset; - protected byte ttl; - protected byte protocol; - protected short checksum; - protected int sourceAddress; - protected int destinationAddress; - protected byte[] options; - - protected boolean isTruncated; - - /** - * Default constructor that sets the version to 4. - */ - public IPv4() { - super(); - this.version = 4; - this.isTruncated = false; - } - - /** - * @return the version - */ - public byte getVersion() { - return this.version; - } - - /** - * @param version - * the version to set - * @return this - */ - public IPv4 setVersion(final byte version) { - this.version = version; - return this; - } - - /** - * @return the headerLength - */ - public byte getHeaderLength() { - return this.headerLength; - } - - /** - * Gets the DSCP value (6 bits). - * - * @return the DSCP value (6 bits) - */ - public byte getDscp() { - return (byte) ((this.diffServ >>> DSCP_OFFSET) & DSCP_MASK); - } - - /** - * Sets the DSCP value (6 bits). - * - * @param dscp the DSCP value (6 bits) - * @return this - */ - public IPv4 setDscp(byte dscp) { - this.diffServ &= ~(DSCP_MASK << DSCP_OFFSET); - this.diffServ |= (dscp & DSCP_MASK) << DSCP_OFFSET; - return this; - } - - /** - * Gets the ECN value (2 bits). - * - * @return the ECN value (2 bits) - */ - public byte getEcn() { - return (byte) (this.diffServ & ECN_MASK); - } - - /** - * Sets the ECN value (2 bits). - * - * @param ecn the ECN value (2 bits) - * @return this - */ - public IPv4 setEcn(byte ecn) { - this.diffServ &= ~ECN_MASK; - this.diffServ |= (ecn & ECN_MASK); - return this; - } - - /** - * Gets the DiffServ octet (including the DSCP and ECN bits). - * - * @return the diffServ octet (including the DSCP and ECN bits) - */ - public byte getDiffServ() { - return this.diffServ; - } - - /** - * Sets the DiffServ octet (including the DSCP and ECN bits). - * - * @param diffServ the diffServ octet to set (including the DSCP and ECN - * bits) - * @return this - */ - public IPv4 setDiffServ(final byte diffServ) { - this.diffServ = diffServ; - return this; - } - - /** - * @return the totalLength - */ - public short getTotalLength() { - return this.totalLength; - } - - /** - * @return the identification - */ - public short getIdentification() { - return this.identification; - } - - public boolean isTruncated() { - return this.isTruncated; - } - - public void setTruncated(final boolean isTruncated) { - this.isTruncated = isTruncated; - } - - /** - * @param identification - * the identification to set - * @return this - */ - public IPv4 setIdentification(final short identification) { - this.identification = identification; - return this; - } - - /** - * @return the flags - */ - public byte getFlags() { - return this.flags; - } - - /** - * @param flags - * the flags to set - * @return this -s */ - public IPv4 setFlags(final byte flags) { - this.flags = flags; - return this; - } - - /** - * @return the fragmentOffset - */ - public short getFragmentOffset() { - return this.fragmentOffset; - } - - /** - * @param fragmentOffset - * the fragmentOffset to set - * @return this - */ - public IPv4 setFragmentOffset(final short fragmentOffset) { - this.fragmentOffset = fragmentOffset; - return this; - } - - /** - * @return the ttl - */ - public byte getTtl() { - return this.ttl; - } - - /** - * @param ttl - * the ttl to set - * @return this - */ - public IPv4 setTtl(final byte ttl) { - this.ttl = ttl; - return this; - } - - /** - * @return the protocol - */ - public byte getProtocol() { - return this.protocol; - } - - /** - * @param protocol - * the protocol to set - * @return this - */ - public IPv4 setProtocol(final byte protocol) { - this.protocol = protocol; - return this; - } - - /** - * @return the checksum - */ - public short getChecksum() { - return this.checksum; - } - - /** - * @param checksum - * the checksum to set - * @return this - */ - public IPv4 setChecksum(final short checksum) { - this.checksum = checksum; - return this; - } - - @Override - public void resetChecksum() { - this.checksum = 0; - super.resetChecksum(); - } - - /** - * @return the sourceAddress - */ - public int getSourceAddress() { - return this.sourceAddress; - } - - /** - * @param sourceAddress - * the sourceAddress to set - * @return this - */ - public IPv4 setSourceAddress(final int sourceAddress) { - this.sourceAddress = sourceAddress; - return this; - } - - /** - * @param sourceAddress - * the sourceAddress to set - * @return this - */ - public IPv4 setSourceAddress(final String sourceAddress) { - this.sourceAddress = IPv4.toIPv4Address(sourceAddress); - return this; - } - - /** - * @return the destinationAddress - */ - public int getDestinationAddress() { - return this.destinationAddress; - } - - /** - * @param destinationAddress - * the destinationAddress to set - * @return this - */ - public IPv4 setDestinationAddress(final int destinationAddress) { - this.destinationAddress = destinationAddress; - return this; - } - - /** - * @param destinationAddress - * the destinationAddress to set - * @return this - */ - public IPv4 setDestinationAddress(final String destinationAddress) { - this.destinationAddress = IPv4.toIPv4Address(destinationAddress); - return this; - } - - /** - * @return the options - */ - public byte[] getOptions() { - return this.options; - } - - /** - * @param options - * the options to set - * @return this - */ - public IPv4 setOptions(final byte[] options) { - if (options != null && options.length % 4 > 0) { - throw new IllegalArgumentException( - "Options length must be a multiple of 4"); - } - this.options = options; - return this; - } - - /** - * Serializes the packet. Will compute and set the following fields if they - * are set to specific values at the time serialize is called: -checksum : 0 - * -headerLength : 0 -totalLength : 0 - */ - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - int optionsLength = 0; - if (this.options != null) { - optionsLength = this.options.length / 4; - } - this.headerLength = (byte) (5 + optionsLength); - - this.totalLength = (short) (this.headerLength * 4 + (payloadData == null ? 0 - : payloadData.length)); - - final byte[] data = new byte[this.totalLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put((byte) ((this.version & 0xf) << 4 | this.headerLength & 0xf)); - bb.put(this.diffServ); - bb.putShort(this.totalLength); - bb.putShort(this.identification); - bb.putShort((short) ((this.flags & 0x7) << 13 | this.fragmentOffset & 0x1fff)); - bb.put(this.ttl); - bb.put(this.protocol); - bb.putShort(this.checksum); - bb.putInt(this.sourceAddress); - bb.putInt(this.destinationAddress); - if (this.options != null) { - bb.put(this.options); - } - if (payloadData != null) { - bb.put(payloadData); - } - - // compute checksum if needed - if (this.checksum == 0) { - bb.rewind(); - int accumulation = 0; - for (int i = 0; i < this.headerLength * 2; ++i) { - accumulation += 0xffff & bb.getShort(); - } - accumulation = (accumulation >> 16 & 0xffff) - + (accumulation & 0xffff); - this.checksum = (short) (~accumulation & 0xffff); - bb.putShort(10, this.checksum); - } - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - short sscratch; - - this.version = bb.get(); - this.headerLength = (byte) (this.version & 0xf); - this.version = (byte) (this.version >> 4 & 0xf); - this.diffServ = bb.get(); - this.totalLength = bb.getShort(); - this.identification = bb.getShort(); - sscratch = bb.getShort(); - this.flags = (byte) (sscratch >> 13 & 0x7); - this.fragmentOffset = (short) (sscratch & 0x1fff); - this.ttl = bb.get(); - this.protocol = bb.get(); - this.checksum = bb.getShort(); - this.sourceAddress = bb.getInt(); - this.destinationAddress = bb.getInt(); - - if (this.headerLength > 5) { - final int optionsLength = (this.headerLength - 5) * 4; - this.options = new byte[optionsLength]; - bb.get(this.options); - } - - if (this.totalLength != length) { - this.isTruncated = true; - } else { - this.isTruncated = false; - } - - Deserializer<? extends IPacket> deserializer; - if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(this.protocol)) { - deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(this.protocol); - } else { - deserializer = Data.deserializer(); - } - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - - return this; - } - - /** - * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and - * returns the corresponding 32 bit integer. - * - * @param ipAddress ip address in string form - * @return int ip address value - */ - public static int toIPv4Address(final String ipAddress) { - if (ipAddress == null) { - throw new IllegalArgumentException("Specified IPv4 address must" - + "contain 4 sets of numerical digits separated by periods"); - } - final String[] octets = ipAddress.split("\\."); - if (octets.length != 4) { - throw new IllegalArgumentException("Specified IPv4 address must" - + "contain 4 sets of numerical digits separated by periods"); - } - - int result = 0; - for (int i = 0; i < 4; ++i) { - result |= Integer.parseInt(octets[i]) << (3 - i) * 8; - } - return result; - } - - /** - * Accepts an IPv4 address in a byte array and returns the corresponding - * 32-bit integer value. - * - * @param ipAddress ip address in byte form - * @return int ip address value - */ - public static int toIPv4Address(final byte[] ipAddress) { - int ip = 0; - for (int i = 0; i < 4; i++) { - final int t = (ipAddress[i] & 0xff) << (3 - i) * 8; - ip |= t; - } - return ip; - } - - /** - * Accepts an IPv4 address and returns of string of the form xxx.xxx.xxx.xxx, - * e.g., 192.168.0.1. - * - * @param ipAddress ip address in form - * @return string form of ip address - */ - public static String fromIPv4Address(final int ipAddress) { - final StringBuffer sb = new StringBuffer(); - int result = 0; - for (int i = 0; i < 4; ++i) { - result = ipAddress >> (3 - i) * 8 & 0xff; - sb.append(result); - if (i != 3) { - sb.append("."); - } - } - return sb.toString(); - } - - /** - * Accepts a collection of IPv4 addresses as integers and returns a single - * String useful in toString method's containing collections of IP - * addresses. - * - * @param ipAddresses - * collection - * @return ip addresses in comma-separated string form - */ - public static String fromIPv4AddressCollection( - final Collection<Integer> ipAddresses) { - if (ipAddresses == null) { - return "null"; - } - final StringBuffer sb = new StringBuffer(); - sb.append("["); - for (final Integer ip : ipAddresses) { - sb.append(IPv4.fromIPv4Address(ip)); - sb.append(","); - } - sb.replace(sb.length() - 1, sb.length(), "]"); - return sb.toString(); - } - - /** - * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and - * returns the corresponding byte array. - * - * @param ipAddress - * The IP address in the form xx.xxx.xxx.xxx. - * @return The IP address separated into bytes - */ - public static byte[] toIPv4AddressBytes(final String ipAddress) { - final String[] octets = ipAddress.split("\\."); - if (octets.length != 4) { - throw new IllegalArgumentException("Specified IPv4 address must" - + "contain 4 sets of numerical digits separated by periods"); - } - - final byte[] result = new byte[4]; - for (int i = 0; i < 4; ++i) { - result[i] = Integer.valueOf(octets[i]).byteValue(); - } - return result; - } - - /** - * Accepts an IPv4 address in the form of an integer and returns the - * corresponding byte array. - * - * @param ipAddress - * The IP address as an integer. - * @return The IP address separated into bytes. - */ - public static byte[] toIPv4AddressBytes(final int ipAddress) { - return new byte[] {(byte) (ipAddress >>> 24), - (byte) (ipAddress >>> 16), (byte) (ipAddress >>> 8), - (byte) ipAddress}; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - result = prime * result + this.checksum; - result = prime * result + this.destinationAddress; - result = prime * result + this.diffServ; - result = prime * result + this.flags; - result = prime * result + this.fragmentOffset; - result = prime * result + this.headerLength; - result = prime * result + this.identification; - result = prime * result + Arrays.hashCode(this.options); - result = prime * result + this.protocol; - result = prime * result + this.sourceAddress; - result = prime * result + this.totalLength; - result = prime * result + this.ttl; - result = prime * result + this.version; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof IPv4)) { - return false; - } - final IPv4 other = (IPv4) obj; - if (this.checksum != other.checksum) { - return false; - } - if (this.destinationAddress != other.destinationAddress) { - return false; - } - if (this.diffServ != other.diffServ) { - return false; - } - if (this.flags != other.flags) { - return false; - } - if (this.fragmentOffset != other.fragmentOffset) { - return false; - } - if (this.headerLength != other.headerLength) { - return false; - } - if (this.identification != other.identification) { - return false; - } - if (!Arrays.equals(this.options, other.options)) { - return false; - } - if (this.protocol != other.protocol) { - return false; - } - if (this.sourceAddress != other.sourceAddress) { - return false; - } - if (this.totalLength != other.totalLength) { - return false; - } - if (this.ttl != other.ttl) { - return false; - } - if (this.version != other.version) { - return false; - } - return true; - } - - /** - * Deserializer function for IPv4 packets. - * - * @return deserializer function - */ - public static Deserializer<IPv4> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - IPv4 ipv4 = new IPv4(); - - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - byte versionByte = bb.get(); - ipv4.headerLength = (byte) (versionByte & 0xf); - ipv4.setVersion((byte) (versionByte >> 4 & 0xf)); - ipv4.setDiffServ(bb.get()); - ipv4.totalLength = bb.getShort(); - ipv4.identification = bb.getShort(); - short flagsFragment = bb.getShort(); - ipv4.flags = (byte) (flagsFragment >> 13 & 0x7); - ipv4.fragmentOffset = (short) (flagsFragment & 0x1fff); - ipv4.ttl = bb.get(); - ipv4.protocol = bb.get(); - ipv4.checksum = bb.getShort(); - ipv4.sourceAddress = bb.getInt(); - ipv4.destinationAddress = bb.getInt(); - - if (ipv4.headerLength > 5) { - checkHeaderLength(length, ipv4.headerLength * 4); - - int optionsLength = (ipv4.headerLength - 5) * 4; - ipv4.options = new byte[optionsLength]; - bb.get(ipv4.options); - } - - Deserializer<? extends IPacket> deserializer; - if (IPv4.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv4.protocol)) { - deserializer = IPv4.PROTOCOL_DESERIALIZER_MAP.get(ipv4.protocol); - } else { - deserializer = Data.deserializer(); - } - ipv4.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - ipv4.payload.setParent(ipv4); - - if (ipv4.totalLength != length) { - ipv4.isTruncated = true; - } else { - ipv4.isTruncated = false; - } - - return ipv4; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPv6.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPv6.java deleted file mode 100644 index 2e59632a..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IPv6.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.onlab.packet.ipv6.Authentication; -import org.onlab.packet.ipv6.DestinationOptions; -import org.onlab.packet.ipv6.EncapSecurityPayload; -import org.onlab.packet.ipv6.Fragment; -import org.onlab.packet.ipv6.HopByHopOptions; -import org.onlab.packet.ipv6.IExtensionHeader; -import org.onlab.packet.ipv6.Routing; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements IPv6 packet format. (RFC 2460) - */ -public class IPv6 extends BasePacket implements IExtensionHeader { - public static final byte FIXED_HEADER_LENGTH = 40; // bytes - - public static final byte PROTOCOL_TCP = 0x6; - public static final byte PROTOCOL_UDP = 0x11; - public static final byte PROTOCOL_ICMP6 = 0x3A; - public static final byte PROTOCOL_HOPOPT = 0x00; - public static final byte PROTOCOL_ROUTING = 0x2B; - public static final byte PROTOCOL_FRAG = 0x2C; - public static final byte PROTOCOL_ESP = 0x32; - public static final byte PROTOCOL_AH = 0x33; - public static final byte PROTOCOL_DSTOPT = 0x3C; - - - public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = - new HashMap<>(); - - static { - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ICMP6, ICMP6.deserializer()); - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_TCP, TCP.deserializer()); - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_UDP, UDP.deserializer()); - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_HOPOPT, HopByHopOptions.deserializer()); - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ROUTING, Routing.deserializer()); - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_FRAG, Fragment.deserializer()); - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_ESP, EncapSecurityPayload.deserializer()); - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_AH, Authentication.deserializer()); - IPv6.PROTOCOL_DESERIALIZER_MAP.put(IPv6.PROTOCOL_DSTOPT, DestinationOptions.deserializer()); - } - - protected byte version; - protected byte trafficClass; - protected int flowLabel; - protected short payloadLength; - protected byte nextHeader; - protected byte hopLimit; - protected byte[] sourceAddress = new byte[Ip6Address.BYTE_LENGTH]; - protected byte[] destinationAddress = new byte[Ip6Address.BYTE_LENGTH]; - - /** - * Default constructor that sets the version to 6. - */ - public IPv6() { - super(); - this.version = 6; - } - - /** - * Gets IP version. - * - * @return the IP version - */ - public byte getVersion() { - return this.version; - } - - /** - * Sets IP version. - * - * @param version the IP version to set - * @return this - */ - public IPv6 setVersion(final byte version) { - this.version = version; - return this; - } - - /** - * Gets traffic class. - * - * @return the traffic class - */ - public byte getTrafficClass() { - return this.trafficClass; - } - - /** - * Sets traffic class. - * - * @param trafficClass the traffic class to set - * @return this - */ - public IPv6 setTrafficClass(final byte trafficClass) { - this.trafficClass = trafficClass; - return this; - } - - /** - * Gets flow label. - * - * @return the flow label - */ - public int getFlowLabel() { - return this.flowLabel; - } - - /** - * Sets flow label. - * - * @param flowLabel the flow label to set - * @return this - */ - public IPv6 setFlowLabel(final int flowLabel) { - this.flowLabel = flowLabel; - return this; - } - - @Override - public byte getNextHeader() { - return this.nextHeader; - } - - @Override - public IPv6 setNextHeader(final byte nextHeader) { - this.nextHeader = nextHeader; - return this; - } - - /** - * Gets hop limit. - * - * @return the hop limit - */ - public byte getHopLimit() { - return this.hopLimit; - } - - /** - * Sets hop limit. - * - * @param hopLimit the hop limit to set - * @return this - */ - public IPv6 setHopLimit(final byte hopLimit) { - this.hopLimit = hopLimit; - return this; - } - - /** - * Gets source address. - * - * @return the IPv6 source address - */ - public byte[] getSourceAddress() { - return this.sourceAddress; - } - - /** - * Sets source address. - * - * @param sourceAddress the IPv6 source address to set - * @return this - */ - public IPv6 setSourceAddress(final byte[] sourceAddress) { - this.sourceAddress = Arrays.copyOfRange(sourceAddress, 0, Ip6Address.BYTE_LENGTH); - return this; - } - - /** - * Gets destination address. - * - * @return the IPv6 destination address - */ - public byte[] getDestinationAddress() { - return this.destinationAddress; - } - - /** - * Sets destination address. - * - * @param destinationAddress the IPv6 destination address to set - * @return this - */ - public IPv6 setDestinationAddress(final byte[] destinationAddress) { - this.destinationAddress = Arrays.copyOfRange(destinationAddress, 0, Ip6Address.BYTE_LENGTH); - return this; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - this.payloadLength = 0; - if (payloadData != null) { - this.payloadLength = (short) payloadData.length; - } - - final byte[] data = new byte[FIXED_HEADER_LENGTH + payloadLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putInt((this.version & 0xf) << 28 | (this.trafficClass & 0xff) << 20 | this.flowLabel & 0xfffff); - bb.putShort(this.payloadLength); - bb.put(this.nextHeader); - bb.put(this.hopLimit); - bb.put(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH); - bb.put(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH); - - if (payloadData != null) { - bb.put(payloadData); - } - - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - int iscratch; - - iscratch = bb.getInt(); - this.version = (byte) (iscratch >> 28 & 0xf); - this.trafficClass = (byte) (iscratch >> 20 & 0xff); - this.flowLabel = iscratch & 0xfffff; - this.payloadLength = bb.getShort(); - this.nextHeader = bb.get(); - this.hopLimit = bb.get(); - bb.get(this.sourceAddress, 0, Ip6Address.BYTE_LENGTH); - bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader); - } else { - deserializer = Data.deserializer(); - } - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - ByteBuffer bb; - bb = ByteBuffer.wrap(this.destinationAddress); - for (int i = 0; i < 4; i++) { - result = prime * result + bb.getInt(); - } - result = prime * result + this.trafficClass; - result = prime * result + this.flowLabel; - result = prime * result + this.hopLimit; - result = prime * result + this.nextHeader; - result = prime * result + this.payloadLength; - bb = ByteBuffer.wrap(this.sourceAddress); - for (int i = 0; i < 4; i++) { - result = prime * result + bb.getInt(); - } - result = prime * result + this.version; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof IPv6)) { - return false; - } - final IPv6 other = (IPv6) obj; - if (!Arrays.equals(this.destinationAddress, other.destinationAddress)) { - return false; - } - if (this.trafficClass != other.trafficClass) { - return false; - } - if (this.flowLabel != other.flowLabel) { - return false; - } - if (this.hopLimit != other.hopLimit) { - return false; - } - if (this.nextHeader != other.nextHeader) { - return false; - } - if (this.payloadLength != other.payloadLength) { - return false; - } - if (!Arrays.equals(this.sourceAddress, other.sourceAddress)) { - return false; - } - return true; - } - - /** - * Deserializer function for IPv6 packets. - * - * @return deserializer function - */ - public static Deserializer<IPv6> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, FIXED_HEADER_LENGTH); - - IPv6 ipv6 = new IPv6(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - int iscratch = bb.getInt(); - - ipv6.version = (byte) (iscratch >> 28 & 0xf); - ipv6.trafficClass = (byte) (iscratch >> 20 & 0xff); - ipv6.flowLabel = iscratch & 0xfffff; - ipv6.payloadLength = bb.getShort(); - ipv6.nextHeader = bb.get(); - ipv6.hopLimit = bb.get(); - bb.get(ipv6.sourceAddress, 0, Ip6Address.BYTE_LENGTH); - bb.get(ipv6.destinationAddress, 0, Ip6Address.BYTE_LENGTH); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(ipv6.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(ipv6.nextHeader); - } else { - deserializer = Data.deserializer(); - } - ipv6.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - ipv6.payload.setParent(ipv6); - - return ipv6; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip4Address.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip4Address.java deleted file mode 100644 index 114f126c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip4Address.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.nio.ByteBuffer; -import java.util.Arrays; - -import com.google.common.net.InetAddresses; - -/** - * A class representing an IPv4 address. - * This class is immutable. - */ -public final class Ip4Address extends IpAddress { - public static final IpAddress.Version VERSION = IpAddress.Version.INET; - public static final int BYTE_LENGTH = IpAddress.INET_BYTE_LENGTH; - public static final int BIT_LENGTH = IpAddress.INET_BIT_LENGTH; - - /** - * Constructor for given IP address version and address octets. - * - * @param value the IP address value stored in network byte order - * (i.e., the most significant byte first) - * @throws IllegalArgumentException if the arguments are invalid - */ - private Ip4Address(byte[] value) { - super(VERSION, value); - } - - /** - * Returns the integer value of this IPv4 address. - * - * @return the IPv4 address's value as an integer - */ - public int toInt() { - ByteBuffer bb = ByteBuffer.wrap(super.toOctets()); - return bb.getInt(); - } - - /** - * Converts an integer into an IPv4 address. - * - * @param value an integer representing an IPv4 address value - * @return an IPv4 address - */ - public static Ip4Address valueOf(int value) { - byte[] bytes = - ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array(); - return new Ip4Address(bytes); - } - - /** - * Converts a byte array into an IPv4 address. - * - * @param value the IPv4 address value stored in network byte order - * (i.e., the most significant byte first) - * @return an IPv4 address - * @throws IllegalArgumentException if the argument is invalid - */ - public static Ip4Address valueOf(byte[] value) { - return new Ip4Address(value); - } - - /** - * Converts a byte array and a given offset from the beginning of the - * array into an IPv4 address. - * <p> - * The IP address is stored in network byte order (i.e., the most - * significant byte first). - * </p> - * @param value the value to use - * @param offset the offset in bytes from the beginning of the byte array - * @return an IPv4 address - * @throws IllegalArgumentException if the arguments are invalid - */ - public static Ip4Address valueOf(byte[] value, int offset) { - IpAddress.checkArguments(VERSION, value, offset); - byte[] bc = Arrays.copyOfRange(value, offset, value.length); - return Ip4Address.valueOf(bc); - } - - /** - * Converts an InetAddress into an IPv4 address. - * - * @param inetAddress the InetAddress value to use. It must contain an IPv4 - * address - * @return an IPv4 address - * @throws IllegalArgumentException if the argument is invalid - */ - public static Ip4Address valueOf(InetAddress inetAddress) { - byte[] bytes = inetAddress.getAddress(); - if (inetAddress instanceof Inet4Address) { - return new Ip4Address(bytes); - } - if ((inetAddress instanceof Inet6Address) || - (bytes.length == INET6_BYTE_LENGTH)) { - final String msg = "Invalid IPv4 version address string: " + - inetAddress.toString(); - throw new IllegalArgumentException(msg); - } - // Use the number of bytes as a hint - if (bytes.length == INET_BYTE_LENGTH) { - return new Ip4Address(bytes); - } - final String msg = "Unrecognized IP version address string: " + - inetAddress.toString(); - throw new IllegalArgumentException(msg); - } - - /** - * Converts an IPv4 string literal (e.g., "10.2.3.4") into an IP address. - * - * @param value an IPv4 address value in string form - * @return an IPv4 address - * @throws IllegalArgumentException if the argument is invalid - */ - public static Ip4Address valueOf(String value) { - InetAddress inetAddress = null; - try { - inetAddress = InetAddresses.forString(value); - } catch (IllegalArgumentException e) { - final String msg = "Invalid IP address string: " + value; - throw new IllegalArgumentException(msg); - } - return valueOf(inetAddress); - } - - /** - * Creates an IPv4 network mask prefix. - * - * @param prefixLength the length of the mask prefix. Must be in the - * interval [0, 32] - * @return a new IPv4 address that contains a mask prefix of the - * specified length - * @throws IllegalArgumentException if the argument is invalid - */ - public static Ip4Address makeMaskPrefix(int prefixLength) { - byte[] mask = IpAddress.makeMaskPrefixArray(VERSION, prefixLength); - return new Ip4Address(mask); - } - - /** - * Creates an IPv4 address by masking it with a network mask of given - * mask length. - * - * @param address the address to mask - * @param prefixLength the length of the mask prefix. Must be in the - * interval [0, 32] - * @return a new IPv4 address that is masked with a mask prefix of the - * specified length - * @throws IllegalArgumentException if the prefix length is invalid - */ - public static Ip4Address makeMaskedAddress(final Ip4Address address, - int prefixLength) { - byte[] net = makeMaskedAddressArray(address, prefixLength); - return Ip4Address.valueOf(net); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java deleted file mode 100644 index fc442c3e..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip4Prefix.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * The class representing an IPv4 network address. - * This class is immutable. - */ -public final class Ip4Prefix extends IpPrefix { - public static final IpAddress.Version VERSION = IpAddress.Version.INET; - // Maximum network mask length - public static final int MAX_MASK_LENGTH = IpPrefix.MAX_INET_MASK_LENGTH; - - /** - * Constructor for given IPv4 address, and a prefix length. - * - * @param address the IPv4 address - * @param prefixLength the prefix length - * @throws IllegalArgumentException if the prefix length value is invalid - */ - private Ip4Prefix(Ip4Address address, int prefixLength) { - super(address, prefixLength); - } - - /** - * Returns the IPv4 address value of the prefix. - * - * @return the IPv4 address value of the prefix - */ - public Ip4Address address() { - IpAddress a = super.address(); - return (Ip4Address) a; - } - - /** - * Converts an integer and a prefix length into an IPv4 prefix. - * - * @param address an integer representing the IPv4 address - * @param prefixLength the prefix length - * @return an IPv4 prefix - * @throws IllegalArgumentException if the prefix length value is invalid - */ - public static Ip4Prefix valueOf(int address, int prefixLength) { - return new Ip4Prefix(Ip4Address.valueOf(address), prefixLength); - } - - /** - * Converts a byte array and a prefix length into an IPv4 prefix. - * - * @param address the IPv4 address value stored in network byte order - * @param prefixLength the prefix length - * @return an IPv4 prefix - * @throws IllegalArgumentException if the prefix length value is invalid - */ - public static Ip4Prefix valueOf(byte[] address, int prefixLength) { - return new Ip4Prefix(Ip4Address.valueOf(address), prefixLength); - } - - /** - * Converts an IPv4 address and a prefix length into an IPv4 prefix. - * - * @param address the IPv4 address - * @param prefixLength the prefix length - * @return an IPv4 prefix - * @throws IllegalArgumentException if the prefix length value is invalid - */ - public static Ip4Prefix valueOf(Ip4Address address, int prefixLength) { - return new Ip4Prefix(address, prefixLength); - } - - /** - * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") - * into an IPv4 prefix. - * - * @param address an IP prefix in string form (e.g., "10.1.0.0/16") - * @return an IPv4 prefix - * @throws IllegalArgumentException if the arguments are invalid - */ - public static Ip4Prefix valueOf(String address) { - final String[] parts = address.split("/"); - if (parts.length != 2) { - String msg = "Malformed IPv4 prefix string: " + address + ". " + - "Address must take form \"x.x.x.x/y\""; - throw new IllegalArgumentException(msg); - } - Ip4Address ipAddress = Ip4Address.valueOf(parts[0]); - int prefixLength = Integer.parseInt(parts[1]); - - return new Ip4Prefix(ipAddress, prefixLength); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java deleted file mode 100644 index d353422b..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip6Address.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.util.Arrays; - -import com.google.common.net.InetAddresses; - -/** - * A class representing an IPv6 address. - * This class is immutable. - */ -public final class Ip6Address extends IpAddress { - public static final IpAddress.Version VERSION = IpAddress.Version.INET6; - public static final int BYTE_LENGTH = IpAddress.INET6_BYTE_LENGTH; - public static final int BIT_LENGTH = IpAddress.INET6_BIT_LENGTH; - - /** - * Constructor for given IP address version and address octets. - * - * @param value the IP address value stored in network byte order - * (i.e., the most significant byte first) - * @throws IllegalArgumentException if the arguments are invalid - */ - private Ip6Address(byte[] value) { - super(VERSION, value); - } - - /** - * Converts a byte array into an IPv6 address. - * - * @param value the IPv6 address value stored in network byte order - * (i.e., the most significant byte first) - * @return an IPv6 address - * @throws IllegalArgumentException if the argument is invalid - */ - public static Ip6Address valueOf(byte[] value) { - return new Ip6Address(value); - } - - /** - * Converts a byte array and a given offset from the beginning of the - * array into an IPv6 address. - * <p> - * The IP address is stored in network byte order (i.e., the most - * significant byte first). - * </p> - * @param value the value to use - * @param offset the offset in bytes from the beginning of the byte array - * @return an IPv6 address - * @throws IllegalArgumentException if the arguments are invalid - */ - public static Ip6Address valueOf(byte[] value, int offset) { - IpAddress.checkArguments(VERSION, value, offset); - byte[] bc = Arrays.copyOfRange(value, offset, value.length); - return Ip6Address.valueOf(bc); - } - - /** - * Converts an InetAddress into an IPv6 address. - * - * @param inetAddress the InetAddress value to use. It must contain an IPv6 - * address - * @return an IPv6 address - * @throws IllegalArgumentException if the argument is invalid - */ - public static Ip6Address valueOf(InetAddress inetAddress) { - byte[] bytes = inetAddress.getAddress(); - if (inetAddress instanceof Inet6Address) { - return new Ip6Address(bytes); - } - if ((inetAddress instanceof Inet4Address) || - (bytes.length == INET_BYTE_LENGTH)) { - final String msg = "Invalid IPv6 version address string: " + - inetAddress.toString(); - throw new IllegalArgumentException(msg); - } - // Use the number of bytes as a hint - if (bytes.length == INET6_BYTE_LENGTH) { - return new Ip6Address(bytes); - } - final String msg = "Unrecognized IP version address string: " + - inetAddress.toString(); - throw new IllegalArgumentException(msg); - } - - /** - * Converts an IPv6 string literal (e.g., "1111:2222::8888") into an IP - * address. - * - * @param value an IPv6 address value in string form - * @return an IPv6 address - * @throws IllegalArgumentException if the argument is invalid - */ - public static Ip6Address valueOf(String value) { - InetAddress inetAddress = null; - try { - inetAddress = InetAddresses.forString(value); - } catch (IllegalArgumentException e) { - final String msg = "Invalid IP address string: " + value; - throw new IllegalArgumentException(msg); - } - return valueOf(inetAddress); - } - - /** - * Creates an IPv6 network mask prefix. - * - * @param prefixLength the length of the mask prefix. Must be in the - * interval [0, 128] - * @return a new IPv6 address that contains a mask prefix of the - * specified length - * @throws IllegalArgumentException if the arguments are invalid - */ - public static Ip6Address makeMaskPrefix(int prefixLength) { - byte[] mask = IpAddress.makeMaskPrefixArray(VERSION, prefixLength); - return new Ip6Address(mask); - } - - /** - * Creates an IPv6 address by masking it with a network mask of given - * mask length. - * - * @param address the address to mask - * @param prefixLength the length of the mask prefix. Must be in the - * interval [0, 128] - * @return a new IPv6 address that is masked with a mask prefix of the - * specified length - * @throws IllegalArgumentException if the prefix length is invalid - */ - public static Ip6Address makeMaskedAddress(final Ip6Address address, - int prefixLength) { - byte[] net = makeMaskedAddressArray(address, prefixLength); - return Ip6Address.valueOf(net); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java deleted file mode 100644 index 4ea9099b..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/Ip6Prefix.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * The class representing an IPv6 network address. - * This class is immutable. - */ -public final class Ip6Prefix extends IpPrefix { - public static final IpAddress.Version VERSION = IpAddress.Version.INET6; - // Maximum network mask length - public static final int MAX_MASK_LENGTH = IpPrefix.MAX_INET6_MASK_LENGTH; - - /** - * Constructor for given IPv6 address, and a prefix length. - * - * @param address the IPv6 address - * @param prefixLength the prefix length - * @throws IllegalArgumentException if the prefix length value is invalid - */ - private Ip6Prefix(Ip6Address address, int prefixLength) { - super(address, prefixLength); - } - - /** - * Returns the IPv6 address value of the prefix. - * - * @return the IPv6 address value of the prefix - */ - public Ip6Address address() { - IpAddress a = super.address(); - return (Ip6Address) a; - } - - /** - * Converts a byte array and a prefix length into an IPv6 prefix. - * - * @param address the IPv6 address value stored in network byte order - * @param prefixLength the prefix length - * @return an IPv6 prefix - * @throws IllegalArgumentException if the prefix length value is invalid - */ - public static Ip6Prefix valueOf(byte[] address, int prefixLength) { - return new Ip6Prefix(Ip6Address.valueOf(address), prefixLength); - } - - /** - * Converts an IPv6 address and a prefix length into an IPv6 prefix. - * - * @param address the IPv6 address - * @param prefixLength the prefix length - * @return an IPv6 prefix - * @throws IllegalArgumentException if the prefix length value is invalid - */ - public static Ip6Prefix valueOf(Ip6Address address, int prefixLength) { - return new Ip6Prefix(address, prefixLength); - } - - /** - * Converts a CIDR (slash) notation string (e.g., "1111:2222::/64") - * into an IPv6 prefix. - * - * @param address an IP prefix in string form (e.g.,"1111:2222::/64") - * @return an IPv6 prefix - * @throws IllegalArgumentException if the arguments are invalid - */ - public static Ip6Prefix valueOf(String address) { - final String[] parts = address.split("/"); - if (parts.length != 2) { - String msg = "Malformed IPv6 prefix string: " + address + ". " + - "Address must take form " + - "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\""; - throw new IllegalArgumentException(msg); - } - Ip6Address ipAddress = Ip6Address.valueOf(parts[0]); - int prefixLength = Integer.parseInt(parts[1]); - - return new Ip6Prefix(ipAddress, prefixLength); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpAddress.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpAddress.java deleted file mode 100644 index 5fdd3276..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpAddress.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Objects; -import com.google.common.net.InetAddresses; -import com.google.common.primitives.UnsignedBytes; - - -/** - * A class representing an IP address. - * This class is immutable. - */ -public class IpAddress implements Comparable<IpAddress> { - private static final int BIT_MASK = 0x000000ff; - - // IP Versions - public enum Version { INET, INET6 }; - - // lengths of address, in bytes - public static final int INET_BYTE_LENGTH = 4; - public static final int INET_BIT_LENGTH = INET_BYTE_LENGTH * Byte.SIZE; - public static final int INET6_BYTE_LENGTH = 16; - public static final int INET6_BIT_LENGTH = INET6_BYTE_LENGTH * Byte.SIZE; - - private final Version version; - private final byte[] octets; - - /** - * Constructor for given IP address version and address octets. - * - * @param version the IP address version - * @param value the IP address value stored in network byte order - * (i.e., the most significant byte first) - * @throws IllegalArgumentException if the arguments are invalid - */ - protected IpAddress(Version version, byte[] value) { - checkArguments(version, value, 0); - this.version = version; - switch (version) { - case INET: - this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH); - break; - case INET6: - this.octets = Arrays.copyOf(value, INET6_BYTE_LENGTH); - break; - default: - // Should not be reached - this.octets = null; - break; - } - } - - /** - * Returns the IP version of this address. - * - * @return the version - */ - public Version version() { - return this.version; - } - - /** - * Tests whether the IP version of this address is IPv4. - * - * @return true if the IP version of this address is IPv4, otherwise false. - */ - public boolean isIp4() { - return (version() == Ip4Address.VERSION); - } - - /** - * Tests whether the IP version of this address is IPv6. - * - * @return true if the IP version of this address is IPv6, otherwise false. - */ - public boolean isIp6() { - return (version() == Ip6Address.VERSION); - } - - /** - * Gets the {@link Ip4Address} view of the IP address. - * - * @return the {@link Ip4Address} view of the IP address if it is IPv4, - * otherwise null - */ - public Ip4Address getIp4Address() { - if (!isIp4()) { - return null; - } - - // Return this object itself if it is already instance of Ip4Address - if (this instanceof Ip4Address) { - return (Ip4Address) this; - } - return Ip4Address.valueOf(octets); - } - - /** - * Gets the {@link Ip6Address} view of the IP address. - * - * @return the {@link Ip6Address} view of the IP address if it is IPv6, - * otherwise null - */ - public Ip6Address getIp6Address() { - if (!isIp6()) { - return null; - } - - // Return this object itself if it is already instance of Ip6Address - if (this instanceof Ip6Address) { - return (Ip6Address) this; - } - return Ip6Address.valueOf(octets); - } - - /** - * Returns the IP address as a byte array. - * - * @return a byte array - */ - public byte[] toOctets() { - return Arrays.copyOf(octets, octets.length); - } - - /** - * Computes the IP address byte length for a given IP version. - * - * @param version the IP version - * @return the IP address byte length for the IP version - * @throws IllegalArgumentException if the IP version is invalid - */ - public static int byteLength(Version version) { - switch (version) { - case INET: - return INET_BYTE_LENGTH; - case INET6: - return INET6_BYTE_LENGTH; - default: - String msg = "Invalid IP version " + version; - throw new IllegalArgumentException(msg); - } - } - - /** - * Converts an integer into an IPv4 address. - * - * @param value an integer representing an IPv4 address value - * @return an IP address - */ - public static IpAddress valueOf(int value) { - byte[] bytes = - ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array(); - return new IpAddress(Version.INET, bytes); - } - - /** - * Converts a byte array into an IP address. - * - * @param version the IP address version - * @param value the IP address value stored in network byte order - * (i.e., the most significant byte first) - * @return an IP address - * @throws IllegalArgumentException if the arguments are invalid - */ - public static IpAddress valueOf(Version version, byte[] value) { - return new IpAddress(version, value); - } - - /** - * Converts a byte array and a given offset from the beginning of the - * array into an IP address. - * <p> - * The IP address is stored in network byte order (i.e., the most - * significant byte first). - * </p> - * @param version the IP address version - * @param value the value to use - * @param offset the offset in bytes from the beginning of the byte array - * @return an IP address - * @throws IllegalArgumentException if the arguments are invalid - */ - public static IpAddress valueOf(Version version, byte[] value, - int offset) { - checkArguments(version, value, offset); - byte[] bc = Arrays.copyOfRange(value, offset, value.length); - return IpAddress.valueOf(version, bc); - } - - /** - * Converts an InetAddress into an IP address. - * - * @param inetAddress the InetAddress value to use - * @return an IP address - * @throws IllegalArgumentException if the argument is invalid - */ - public static IpAddress valueOf(InetAddress inetAddress) { - byte[] bytes = inetAddress.getAddress(); - if (inetAddress instanceof Inet4Address) { - return new IpAddress(Version.INET, bytes); - } - if (inetAddress instanceof Inet6Address) { - return new IpAddress(Version.INET6, bytes); - } - // Use the number of bytes as a hint - if (bytes.length == INET_BYTE_LENGTH) { - return new IpAddress(Version.INET, bytes); - } - if (bytes.length == INET6_BYTE_LENGTH) { - return new IpAddress(Version.INET6, bytes); - } - final String msg = "Unrecognized IP version address string: " + - inetAddress.toString(); - throw new IllegalArgumentException(msg); - } - - /** - * Converts an IPv4 or IPv6 string literal (e.g., "10.2.3.4" or - * "1111:2222::8888") into an IP address. - * - * @param value an IP address value in string form - * @return an IP address - * @throws IllegalArgumentException if the argument is invalid - */ - public static IpAddress valueOf(String value) { - InetAddress inetAddress = null; - try { - inetAddress = InetAddresses.forString(value); - } catch (IllegalArgumentException e) { - final String msg = "Invalid IP address string: " + value; - throw new IllegalArgumentException(msg); - } - return valueOf(inetAddress); - } - - /** - * Creates an IP network mask prefix. - * - * @param version the IP address version - * @param prefixLength the length of the mask prefix. Must be in the - * interval [0, 32] for IPv4, or [0, 128] for IPv6 - * @return a new IP address that contains a mask prefix of the - * specified length - * @throws IllegalArgumentException if the arguments are invalid - */ - public static IpAddress makeMaskPrefix(Version version, int prefixLength) { - byte[] mask = makeMaskPrefixArray(version, prefixLength); - return new IpAddress(version, mask); - } - - /** - * Creates an IP address by masking it with a network mask of given - * mask length. - * - * @param address the address to mask - * @param prefixLength the length of the mask prefix. Must be in the - * interval [0, 32] for IPv4, or [0, 128] for IPv6 - * @return a new IP address that is masked with a mask prefix of the - * specified length - * @throws IllegalArgumentException if the prefix length is invalid - */ - public static IpAddress makeMaskedAddress(final IpAddress address, - int prefixLength) { - if (address instanceof Ip4Address) { - Ip4Address ip4a = (Ip4Address) address; - return Ip4Address.makeMaskedAddress(ip4a, prefixLength); - } else if (address instanceof Ip6Address) { - Ip6Address ip6a = (Ip6Address) address; - return Ip6Address.makeMaskedAddress(ip6a, prefixLength); - } else { - byte[] net = makeMaskedAddressArray(address, prefixLength); - return IpAddress.valueOf(address.version(), net); - } - } - - /** - * Check if this IP address is zero. - * - * @return true if this address is zero - */ - public boolean isZero() { - for (byte b : octets) { - if (b != 0) { - return false; - } - } - return true; - } - - /** - * Check if this IP address is self-assigned. - * - * @return true if this address is self-assigned - */ - public boolean isSelfAssigned() { - return isIp4() && octets[0] == (byte) 169; - } - - @Override - public int compareTo(IpAddress o) { - // Compare first the version - if (this.version != o.version) { - return this.version.compareTo(o.version); - } - - // Compare the bytes, one-by-one - for (int i = 0; i < this.octets.length; i++) { - if (this.octets[i] != o.octets[i]) { - return UnsignedBytes.compare(this.octets[i], o.octets[i]); - } - } - return 0; // Equal - } - - @Override - public int hashCode() { - return Objects.hash(version, Arrays.hashCode(octets)); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if ((obj == null) || (!(obj instanceof IpAddress))) { - return false; - } - IpAddress other = (IpAddress) obj; - return (version == other.version) && - Arrays.equals(octets, other.octets); - } - - @Override - /* - * (non-Javadoc) - * The string representation of the IP address: "x.x.x.x" for IPv4 - * addresses, or ':' separated string for IPv6 addresses. - * - * @see java.lang.Object#toString() - */ - public String toString() { - // FIXME InetAddress is super slow - switch (version) { - case INET: - return String.format("%d.%d.%d.%d", octets[0] & 0xff, - octets[1] & 0xff, - octets[2] & 0xff, - octets[3] & 0xff); - case INET6: - default: - return ipv6ToStringHelper(); - } - } - - /** - * Generates an IP prefix. - * - * @return the IP prefix of the IP address - */ - public IpPrefix toIpPrefix() { - - if (isIp4()) { - return IpPrefix.valueOf(new IpAddress(Version.INET, octets), - Ip4Address.BIT_LENGTH); - } else { - return IpPrefix.valueOf(new IpAddress(Version.INET6, octets), - Ip6Address.BIT_LENGTH); - } - } - - /** - * Gets the IP address name for the IP address version. - * - * @param version the IP address version - * @return the IP address name for the IP address version - */ - private static String addressName(Version version) { - switch (version) { - case INET: - return "IPv4"; - case INET6: - return "IPv6"; - default: - break; - } - return "UnknownIP(" + version + ")"; - } - - /** - * Checks whether the arguments are valid. - * - * @param version the IP address version - * @param value the IP address value stored in a byte array - * @param offset the offset in bytes from the beginning of the byte - * array with the address - * @throws IllegalArgumentException if any of the arguments is invalid - */ - static void checkArguments(Version version, byte[] value, int offset) { - // Check the offset and byte array length - int addrByteLength = byteLength(version); - if ((offset < 0) || (offset + addrByteLength > value.length)) { - String msg; - if (value.length < addrByteLength) { - msg = "Invalid " + addressName(version) + - " address array: array length: " + value.length + - ". Must be at least " + addrByteLength; - } else { - msg = "Invalid " + addressName(version) + - " address array: array offset: " + offset + - ". Must be in the interval [0, " + - (value.length - addrByteLength) + "]"; - } - throw new IllegalArgumentException(msg); - } - } - - /** - * Creates a byte array for IP network mask prefix. - * - * @param version the IP address version - * @param prefixLength the length of the mask prefix. Must be in the - * interval [0, 32] for IPv4, or [0, 128] for IPv6 - * @return a byte array that contains a mask prefix of the - * specified length - * @throws IllegalArgumentException if the arguments are invalid - */ - static byte[] makeMaskPrefixArray(Version version, int prefixLength) { - int addrByteLength = byteLength(version); - int addrBitLength = addrByteLength * Byte.SIZE; - - // Verify the prefix length - if ((prefixLength < 0) || (prefixLength > addrBitLength)) { - final String msg = "Invalid IP prefix length: " + prefixLength + - ". Must be in the interval [0, " + addrBitLength + "]."; - throw new IllegalArgumentException(msg); - } - - // Number of bytes and extra bits that should be all 1s - int maskBytes = prefixLength / Byte.SIZE; - int maskBits = prefixLength % Byte.SIZE; - byte[] mask = new byte[addrByteLength]; - - // Set the bytes and extra bits to 1s - for (int i = 0; i < maskBytes; i++) { - mask[i] = (byte) 0xff; // Set mask bytes to 1s - } - for (int i = maskBytes; i < addrByteLength; i++) { - mask[i] = 0; // Set remaining bytes to 0s - } - if (maskBits > 0) { - mask[maskBytes] = (byte) (0xff << (Byte.SIZE - maskBits)); - } - return mask; - } - - /** - * Creates a byte array that represents an IP address masked with - * a network mask of given mask length. - * - * @param addr the address to mask - * @param prefixLength the length of the mask prefix. Must be in the - * interval [0, 32] for IPv4, or [0, 128] for IPv6 - * @return a byte array that represents the IP address masked with - * a mask prefix of the specified length - * @throws IllegalArgumentException if the prefix length is invalid - */ - static byte[] makeMaskedAddressArray(final IpAddress addr, - int prefixLength) { - byte[] mask = IpAddress.makeMaskPrefixArray(addr.version(), - prefixLength); - byte[] net = new byte[mask.length]; - - // Mask each byte - for (int i = 0; i < net.length; i++) { - net[i] = (byte) (addr.octets[i] & mask[i]); - } - return net; - } - - /** - * Creates a string based on the IPv6 recommendations for canonical representations found here: - * https://tools.ietf.org/html/rfc5952#section-1. - * @return A properly formatted IPv6 canonical representation. - */ - private String ipv6ToStringHelper() { - //Populate a buffer with the string of the full address with leading zeros stripped - StringBuffer buff = new StringBuffer(); - buff.append(String.format("%x:%x:%x:%x:%x:%x:%x:%x", - (((octets[0] & BIT_MASK) << 8) | (octets[1] & BIT_MASK)), - (((octets[2] & BIT_MASK) << 8) | (octets[3] & BIT_MASK)), - (((octets[4] & BIT_MASK) << 8) | (octets[5] & BIT_MASK)), - (((octets[6] & BIT_MASK) << 8) | (octets[7] & BIT_MASK)), - (((octets[8] & BIT_MASK) << 8) | (octets[9] & BIT_MASK)), - (((octets[10] & BIT_MASK) << 8) | (octets[11] & BIT_MASK)), - (((octets[12] & BIT_MASK) << 8) | (octets[13] & BIT_MASK)), - (((octets[14] & BIT_MASK) << 8) | (octets[15] & BIT_MASK)))); - //Initialize variables for tracking longest zero subsequence, tiebreaking by first occurence - int longestSeqStart, longestSeqLen, currSeqStart, currSeqLen; - longestSeqStart = 0; - longestSeqLen = 0; - currSeqStart = 0; - currSeqLen = 0; - - for (int index = 0; index < buff.length(); index++) { - if (buff.charAt(index) == ':') { - if (currSeqLen != 0 && buff.charAt(index + 1) == '0') { - currSeqLen += 1; - } - } else if (buff.charAt(index) == '0' && ((index == 0) || (buff.charAt(index - 1) == ':'))) { - if (currSeqLen == 0) { - currSeqStart = index; - } - currSeqLen += 1; - } else { - if (currSeqLen > longestSeqLen) { - longestSeqStart = currSeqStart; - longestSeqLen = currSeqLen; - } - currSeqLen = 0; - } - } - - if (currSeqLen > longestSeqLen) { - longestSeqLen = currSeqLen; - longestSeqStart = currSeqStart; - } - if (longestSeqLen > 1) { - if (buff.length() == (longestSeqStart + longestSeqLen)) { - buff.append(':'); - } - - buff.delete(longestSeqStart, longestSeqStart + longestSeqLen); - - if (longestSeqStart == 0) { - buff.insert(0, ':'); - } - } - - return buff.toString(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java deleted file mode 100644 index 14d07fed..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/IpPrefix.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.util.Objects; - -/** - * A class representing an IP prefix. A prefix consists of an IP address and - * a subnet mask. - * This class is immutable. - * <p> - * NOTE: The stored IP address in the result IP prefix is masked to - * contain zeroes in all bits after the prefix length. - * </p> - */ -public class IpPrefix { - // Maximum network mask length - public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH; - public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH; - - private final IpAddress address; - private final short prefixLength; - - /** - * Constructor for given IP address, and a prefix length. - * - * @param address the IP address - * @param prefixLength the prefix length - * @throws IllegalArgumentException if the prefix length value is invalid - */ - protected IpPrefix(IpAddress address, int prefixLength) { - checkPrefixLength(address.version(), prefixLength); - this.address = IpAddress.makeMaskedAddress(address, prefixLength); - this.prefixLength = (short) prefixLength; - } - - /** - * Returns the IP version of the prefix. - * - * @return the IP version of the prefix - */ - public IpAddress.Version version() { - return address.version(); - } - - /** - * Tests whether the IP version of this prefix is IPv4. - * - * @return true if the IP version of this prefix is IPv4, otherwise false. - */ - public boolean isIp4() { - return address.isIp4(); - } - - /** - * Tests whether the IP version of this prefix is IPv6. - * - * @return true if the IP version of this prefix is IPv6, otherwise false. - */ - public boolean isIp6() { - return address.isIp6(); - } - - /** - * Returns the IP address value of the prefix. - * - * @return the IP address value of the prefix - */ - public IpAddress address() { - return address; - } - - /** - * Returns the IP address prefix length. - * - * @return the IP address prefix length - */ - public int prefixLength() { - return prefixLength; - } - - /** - * Gets the {@link Ip4Prefix} view of the IP prefix. - * - * @return the {@link Ip4Prefix} view of the IP prefix if it is IPv4, - * otherwise null - */ - public Ip4Prefix getIp4Prefix() { - if (!isIp4()) { - return null; - } - - // Return this object itself if it is already instance of Ip4Prefix - if (this instanceof Ip4Prefix) { - return (Ip4Prefix) this; - } - return Ip4Prefix.valueOf(address.getIp4Address(), prefixLength); - } - - /** - * Gets the {@link Ip6Prefix} view of the IP prefix. - * - * @return the {@link Ip6Prefix} view of the IP prefix if it is IPv6, - * otherwise null - */ - public Ip6Prefix getIp6Prefix() { - if (!isIp6()) { - return null; - } - - // Return this object itself if it is already instance of Ip6Prefix - if (this instanceof Ip6Prefix) { - return (Ip6Prefix) this; - } - return Ip6Prefix.valueOf(address.getIp6Address(), prefixLength); - } - - /** - * Converts an integer and a prefix length into an IPv4 prefix. - * - * @param address an integer representing the IPv4 address - * @param prefixLength the prefix length - * @return an IP prefix - * @throws IllegalArgumentException if the prefix length value is invalid - */ - public static IpPrefix valueOf(int address, int prefixLength) { - return new IpPrefix(IpAddress.valueOf(address), prefixLength); - } - - /** - * Converts a byte array and a prefix length into an IP prefix. - * - * @param version the IP address version - * @param address the IP address value stored in network byte order - * @param prefixLength the prefix length - * @return an IP prefix - * @throws IllegalArgumentException if the prefix length value is invalid - */ - public static IpPrefix valueOf(IpAddress.Version version, byte[] address, - int prefixLength) { - return new IpPrefix(IpAddress.valueOf(version, address), prefixLength); - } - - /** - * Converts an IP address and a prefix length into an IP prefix. - * - * @param address the IP address - * @param prefixLength the prefix length - * @return an IP prefix - * @throws IllegalArgumentException if the prefix length value is invalid - */ - public static IpPrefix valueOf(IpAddress address, int prefixLength) { - return new IpPrefix(address, prefixLength); - } - - /** - * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16" or - * "1111:2222::/64") into an IP prefix. - * - * @param address an IP prefix in string form (e.g. "10.1.0.0/16" or - * "1111:2222::/64") - * @return an IP prefix - * @throws IllegalArgumentException if the arguments are invalid - */ - public static IpPrefix valueOf(String address) { - final String[] parts = address.split("/"); - if (parts.length != 2) { - String msg = "Malformed IP prefix string: " + address + ". " + - "Address must take form \"x.x.x.x/y\" or " + - "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\""; - throw new IllegalArgumentException(msg); - } - IpAddress ipAddress = IpAddress.valueOf(parts[0]); - int prefixLength = Integer.parseInt(parts[1]); - - return new IpPrefix(ipAddress, prefixLength); - } - - /** - * Determines whether a given IP prefix is contained within this prefix. - * - * @param other the IP prefix to test - * @return true if the other IP prefix is contained in this prefix, - * otherwise false - */ - public boolean contains(IpPrefix other) { - if (version() != other.version()) { - return false; - } - - if (this.prefixLength > other.prefixLength) { - return false; // This prefix has smaller prefix size - } - - // - // Mask the other address with my prefix length. - // If the other prefix is within this prefix, the masked address must - // be same as the address of this prefix. - // - IpAddress maskedAddr = - IpAddress.makeMaskedAddress(other.address, this.prefixLength); - return this.address.equals(maskedAddr); - } - - /** - * Determines whether a given IP address is contained within this prefix. - * - * @param other the IP address to test - * @return true if the IP address is contained in this prefix, otherwise - * false - */ - public boolean contains(IpAddress other) { - if (version() != other.version()) { - return false; - } - - // - // Mask the other address with my prefix length. - // If the other prefix is within this prefix, the masked address must - // be same as the address of this prefix. - // - IpAddress maskedAddr = - IpAddress.makeMaskedAddress(other, this.prefixLength); - return this.address.equals(maskedAddr); - } - - @Override - public int hashCode() { - return Objects.hash(address, prefixLength); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if ((obj == null) || (!(obj instanceof IpPrefix))) { - return false; - } - IpPrefix other = (IpPrefix) obj; - return ((prefixLength == other.prefixLength) && - address.equals(other.address)); - } - - @Override - /* - * (non-Javadoc) - * The format is "x.x.x.x/y" for IPv4 prefixes. - * - * @see java.lang.Object#toString() - */ - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append(address.toString()); - builder.append("/"); - builder.append(String.format("%d", prefixLength)); - return builder.toString(); - } - - /** - * Checks whether the prefix length is valid. - * - * @param version the IP address version - * @param prefixLength the prefix length value to check - * @throws IllegalArgumentException if the prefix length value is invalid - */ - private static void checkPrefixLength(IpAddress.Version version, - int prefixLength) { - int maxPrefixLen = 0; - - switch (version) { - case INET: - maxPrefixLen = MAX_INET_MASK_LENGTH; - break; - case INET6: - maxPrefixLen = MAX_INET6_MASK_LENGTH; - break; - default: - String msg = "Invalid IP version " + version; - throw new IllegalArgumentException(msg); - } - - if ((prefixLength < 0) || (prefixLength > maxPrefixLen)) { - String msg = "Invalid prefix length " + prefixLength + ". " + - "The value must be in the interval [0, " + - maxPrefixLen + "]"; - throw new IllegalArgumentException(msg); - } - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLC.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLC.java deleted file mode 100644 index 78b4f3fa..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLC.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.*; - -/** - * This class represents an Link Local Control header that is used in Ethernet - * 802.3. - * - * - */ -public class LLC extends BasePacket { - - public static final byte LLC_HEADER_LENGTH = 3; - - private byte dsap = 0; - private byte ssap = 0; - private byte ctrl = 0; - - public byte getDsap() { - return this.dsap; - } - - public void setDsap(final byte dsap) { - this.dsap = dsap; - } - - public byte getSsap() { - return this.ssap; - } - - public void setSsap(final byte ssap) { - this.ssap = ssap; - } - - public byte getCtrl() { - return this.ctrl; - } - - public void setCtrl(final byte ctrl) { - this.ctrl = ctrl; - } - - @Override - public byte[] serialize() { - final byte[] data = new byte[3]; - final ByteBuffer bb = ByteBuffer.wrap(data); - bb.put(this.dsap); - bb.put(this.ssap); - bb.put(this.ctrl); - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.dsap = bb.get(); - this.ssap = bb.get(); - this.ctrl = bb.get(); - return this; - } - - /** - * Deserializer function for LLC packets. - * - * @return deserializer function - */ - public static Deserializer<LLC> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, LLC_HEADER_LENGTH); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - LLC llc = new LLC(); - - llc.dsap = bb.get(); - llc.ssap = bb.get(); - llc.ctrl = bb.get(); - - return llc; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDP.java deleted file mode 100644 index ae9d7173..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDP.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.LinkedList; -import java.util.List; - -import static org.onlab.packet.PacketUtils.*; - -/** - * - */ -public class LLDP extends BasePacket { - public static final byte CHASSIS_TLV_TYPE = 1; - public static final short CHASSIS_TLV_SIZE = 7; - public static final byte CHASSIS_TLV_SUBTYPE = 4; - - public static final byte PORT_TLV_TYPE = 2; - public static final short PORT_TLV_SIZE = 5; - public static final byte PORT_TLV_SUBTYPE = 2; - - public static final byte TTL_TLV_TYPE = 3; - public static final short TTL_TLV_SIZE = 2; - - protected LLDPTLV chassisId; - protected LLDPTLV portId; - protected LLDPTLV ttl; - protected List<LLDPTLV> optionalTLVList; - protected short ethType; - - public LLDP() { - this.optionalTLVList = new LinkedList<>(); - this.ethType = Ethernet.TYPE_LLDP; - } - - /** - * @return the chassisId - */ - public LLDPTLV getChassisId() { - return this.chassisId; - } - - /** - * @param chassis - * the chassisId to set - * @return this - */ - public LLDP setChassisId(final LLDPTLV chassis) { - this.chassisId = chassis; - return this; - } - - /** - * @return the portId - */ - public LLDPTLV getPortId() { - return this.portId; - } - - /** - * @param portId - * the portId to set - * @return this - */ - public LLDP setPortId(final LLDPTLV portId) { - this.portId = portId; - return this; - } - - /** - * @return the ttl - */ - public LLDPTLV getTtl() { - return this.ttl; - } - - /** - * @param ttl - * the ttl to set - * @return this - */ - public LLDP setTtl(final LLDPTLV ttl) { - this.ttl = ttl; - return this; - } - - /** - * @return the optionalTLVList - */ - public List<LLDPTLV> getOptionalTLVList() { - return this.optionalTLVList; - } - - /** - * @param optionalTLVList - * the optionalTLVList to set - * @return this - */ - public LLDP setOptionalTLVList(final List<LLDPTLV> optionalTLVList) { - this.optionalTLVList = optionalTLVList; - return this; - } - - @Override - public byte[] serialize() { - int length = 2 + this.chassisId.getLength() + 2 - + this.portId.getLength() + 2 + this.ttl.getLength() + 2; - for (final LLDPTLV tlv : this.optionalTLVList) { - length += 2 + tlv.getLength(); - } - - final byte[] data = new byte[length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - bb.put(this.chassisId.serialize()); - bb.put(this.portId.serialize()); - bb.put(this.ttl.serialize()); - for (final LLDPTLV tlv : this.optionalTLVList) { - bb.put(tlv.serialize()); - } - bb.putShort((short) 0); // End of LLDPDU - - /* - * if (this.parent != null && this.parent instanceof Ethernet) { - * ((Ethernet) this.parent).setEtherType(this.ethType); } - */ - - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - LLDPTLV tlv; - do { - try { - tlv = new LLDPOrganizationalTLV().deserialize(bb); - } catch (DeserializationException e) { - break; - } - - // if there was a failure to deserialize stop processing TLVs - if (tlv == null) { - break; - } - switch (tlv.getType()) { - case 0x0: - // can throw this one away, its just an end delimiter - break; - case 0x1: - this.chassisId = tlv; - break; - case 0x2: - this.portId = tlv; - break; - case 0x3: - this.ttl = tlv; - break; - - default: - this.optionalTLVList.add(tlv); - break; - } - } while (tlv.getType() != 0 && bb.hasRemaining()); - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 883; - int result = super.hashCode(); - result = prime * result - + (this.chassisId == null ? 0 : this.chassisId.hashCode()); - result = prime * result + this.optionalTLVList.hashCode(); - result = prime * result - + (this.portId == null ? 0 : this.portId.hashCode()); - result = prime * result + (this.ttl == null ? 0 : this.ttl.hashCode()); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof LLDP)) { - return false; - } - final LLDP other = (LLDP) obj; - if (this.chassisId == null) { - if (other.chassisId != null) { - return false; - } - } else if (!this.chassisId.equals(other.chassisId)) { - return false; - } - if (!this.optionalTLVList.equals(other.optionalTLVList)) { - return false; - } - if (this.portId == null) { - if (other.portId != null) { - return false; - } - } else if (!this.portId.equals(other.portId)) { - return false; - } - if (this.ttl == null) { - if (other.ttl != null) { - return false; - } - } else if (!this.ttl.equals(other.ttl)) { - return false; - } - return true; - } - - /** - * Deserializer function for LLDP packets. - * - * @return deserializer function - */ - public static Deserializer<LLDP> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, 0); - - LLDP lldp = new LLDP(); - - int currentIndex = 0; - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - LLDPTLV tlv; - do { - // Each new TLV must be a minimum of 2 bytes - // (containing the type and length fields). - currentIndex += 2; - checkHeaderLength(length, currentIndex); - - tlv = new LLDPOrganizationalTLV().deserialize(bb); - - // if there was a failure to deserialize stop processing TLVs - if (tlv == null) { - break; - } - switch (tlv.getType()) { - case 0x0: - // can throw this one away, it's just an end delimiter - break; - case 0x1: - lldp.chassisId = tlv; - break; - case 0x2: - lldp.portId = tlv; - break; - case 0x3: - lldp.ttl = tlv; - break; - default: - lldp.optionalTLVList.add(tlv); - break; - } - - currentIndex += tlv.getLength(); - } while (tlv.getType() != 0); - - return lldp; - }; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDPOrganizationalTLV.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDPOrganizationalTLV.java deleted file mode 100644 index bedf439f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDPOrganizationalTLV.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ -/** - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.Arrays; - -/** - * The class representing LLDP Organizationally Specific TLV. - * - */ -public class LLDPOrganizationalTLV extends LLDPTLV { - public static final int OUI_LENGTH = 3; - public static final int SUBTYPE_LENGTH = 1; - public static final byte ORGANIZATIONAL_TLV_TYPE = 127; - public static final int MAX_INFOSTRING_LENGTH = 507; - - protected byte[] oui; - protected byte subType; - private byte[] infoString; - - public LLDPOrganizationalTLV() { - this.type = LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE; - } - - /** - * Set the value of OUI. - * - * @param oui - * The value of OUI to be set. - * @return This LLDP Organizationally Specific TLV. - */ - public LLDPOrganizationalTLV setOUI(final byte[] oui) { - if (oui.length != LLDPOrganizationalTLV.OUI_LENGTH) { - throw new IllegalArgumentException("The length of OUI must be " - + LLDPOrganizationalTLV.OUI_LENGTH + ", but it is " - + oui.length); - } - this.oui = Arrays.copyOf(oui, oui.length); - return this; - } - - /** - * Returns the value of the OUI. - * - * @return The value of the OUI . - */ - public byte[] getOUI() { - return Arrays.copyOf(this.oui, this.oui.length); - } - - /** - * Set the value of sub type. - * - * @param subType - * The value of sub type to be set. - * @return This LLDP Organizationally Specific TLV. - */ - public LLDPOrganizationalTLV setSubType(final byte subType) { - this.subType = subType; - return this; - } - - /** - * Returns the value of the sub type. - * - * @return The value of the sub type. - */ - public byte getSubType() { - return this.subType; - } - - /** - * Set the value of information string. - * - * @param infoString - * the byte array of the value of information string. - * @return This LLDP Organizationally Specific TLV. - */ - public LLDPOrganizationalTLV setInfoString(final byte[] infoString) { - if (infoString.length > LLDPOrganizationalTLV.MAX_INFOSTRING_LENGTH) { - throw new IllegalArgumentException( - "The length of infoString cannot exceed " - + LLDPOrganizationalTLV.MAX_INFOSTRING_LENGTH); - } - this.infoString = Arrays.copyOf(infoString, infoString.length); - return this; - } - - /** - * Set the value of information string. The String value is automatically - * converted into byte array with UTF-8 encoding. - * - * @param infoString - * the String value of information string. - * @return This LLDP Organizationally Specific TLV. - */ - public LLDPOrganizationalTLV setInfoString(final String infoString) { - final byte[] infoStringBytes = infoString.getBytes(Charset - .forName("UTF-8")); - return this.setInfoString(infoStringBytes); - } - - /** - * Returns the value of information string. - * - * @return the value of information string. - */ - public byte[] getInfoString() { - return Arrays.copyOf(this.infoString, this.infoString.length); - } - - @Override - public byte[] serialize() { - if (this.type != LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) { - return super.serialize(); - } - final int valueLength = LLDPOrganizationalTLV.OUI_LENGTH - + LLDPOrganizationalTLV.SUBTYPE_LENGTH + this.infoString.length; - this.value = new byte[valueLength]; - final ByteBuffer bb = ByteBuffer.wrap(this.value); - bb.put(this.oui); - bb.put(this.subType); - bb.put(this.infoString); - return super.serialize(); - } - - @Override - public LLDPTLV deserialize(final ByteBuffer bb) throws DeserializationException { - super.deserialize(bb); - if (this.getType() != LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) { - return this; - } - - if (this.getLength() <= OUI_LENGTH + SUBTYPE_LENGTH) { - throw new DeserializationException( - "TLV length is less than required for organizational TLV"); - } - - final ByteBuffer optionalField = ByteBuffer.wrap(this.value); - - final byte[] oui = new byte[LLDPOrganizationalTLV.OUI_LENGTH]; - optionalField.get(oui); - this.setOUI(oui); - - this.setSubType(optionalField.get()); - - final byte[] infoString = new byte[this.getLength() - - LLDPOrganizationalTLV.OUI_LENGTH - - LLDPOrganizationalTLV.SUBTYPE_LENGTH]; - optionalField.get(infoString); - this.setInfoString(infoString); - return this; - } - - @Override - public int hashCode() { - final int prime = 1423; - int result = 1; - result = prime * result + this.type; - result = prime * result + this.length; - result = prime * result + Arrays.hashCode(this.oui); - result = prime * result + this.subType; - result = prime * result + Arrays.hashCode(this.infoString); - return result; - } - - @Override - public boolean equals(final Object o) { - if (o == this) { - return true; - } - - if (!(o instanceof LLDPOrganizationalTLV)) { - return false; - } - - final LLDPOrganizationalTLV other = (LLDPOrganizationalTLV) o; - if (this.type != other.type) { - return false; - } - if (this.length != other.length) { - return false; - } - if (!Arrays.equals(this.oui, other.oui)) { - return false; - } - if (this.subType != other.subType) { - return false; - } - if (!Arrays.equals(this.infoString, other.infoString)) { - return false; - } - - return true; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDPTLV.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDPTLV.java deleted file mode 100644 index 77efe1b7..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/LLDPTLV.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -/** - * - * - */ -public class LLDPTLV { - protected byte type; - protected short length; - protected byte[] value; - - /** - * @return the type - */ - public byte getType() { - return this.type; - } - - /** - * @param type - * the type to set - * @return this - */ - public LLDPTLV setType(final byte type) { - this.type = type; - return this; - } - - /** - * @return the length - */ - public short getLength() { - return this.length; - } - - /** - * @param length - * the length to set - * @return this - */ - public LLDPTLV setLength(final short length) { - this.length = length; - return this; - } - - /** - * @return the value - */ - public byte[] getValue() { - return this.value; - } - - /** - * @param value - * the value to set - * @return this - */ - public LLDPTLV setValue(final byte[] value) { - this.value = value; - return this; - } - - public byte[] serialize() { - // type = 7 bits - // info string length 9 bits, each value == byte - // info string - final short scratch = (short) ((0x7f & this.type) << 9 | 0x1ff & this.length); - final byte[] data = new byte[2 + this.length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - bb.putShort(scratch); - if (this.value != null) { - bb.put(this.value); - } - return data; - } - - public LLDPTLV deserialize(final ByteBuffer bb) throws DeserializationException { - if (bb.remaining() < 2) { - throw new DeserializationException( - "Not enough bytes to deserialize TLV type and length"); - } - short typeLength; - typeLength = bb.getShort(); - this.type = (byte) (typeLength >> 9 & 0x7f); - this.length = (short) (typeLength & 0x1ff); - - if (this.length > 0) { - this.value = new byte[this.length]; - - // if there is an underrun just toss the TLV - if (bb.remaining() < this.length) { - throw new DeserializationException( - "Remaining bytes are less then the length of the TLV"); - } - bb.get(this.value); - } - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 1423; - int result = 1; - result = prime * result + this.length; - result = prime * result + this.type; - result = prime * result + Arrays.hashCode(this.value); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof LLDPTLV)) { - return false; - } - final LLDPTLV other = (LLDPTLV) obj; - if (this.length != other.length) { - return false; - } - if (this.type != other.type) { - return false; - } - if (!Arrays.equals(this.value, other.value)) { - return false; - } - return true; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MPLS.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MPLS.java deleted file mode 100644 index 71c5803e..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MPLS.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; - -import static org.onlab.packet.PacketUtils.checkInput; - -public class MPLS extends BasePacket { - public static final int HEADER_LENGTH = 4; - - public static final byte PROTOCOL_IPV4 = 0x1; - public static final byte PROTOCOL_MPLS = 0x6; - static Map<Byte, Deserializer<? extends IPacket>> protocolDeserializerMap - = new HashMap<>(); - - static { - protocolDeserializerMap.put(PROTOCOL_IPV4, IPv4.deserializer()); - protocolDeserializerMap.put(PROTOCOL_MPLS, MPLS.deserializer()); - } - - protected int label; //20bits - protected byte bos; //1bit - protected byte ttl; //8bits - protected byte protocol; - - /** - * Default constructor that sets the version to 4. - */ - public MPLS() { - super(); - this.bos = 1; - this.protocol = PROTOCOL_IPV4; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (payload != null) { - payload.setParent(this); - payloadData = payload.serialize(); - } - - byte[] data = new byte[(4 + ((payloadData != null) ? payloadData.length : 0)) ]; - ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putInt(((this.label & 0x000fffff) << 12) | ((this.bos & 0x1) << 8 | (this.ttl & 0xff))); - if (payloadData != null) { - bb.put(payloadData); - } - - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - int mplsheader = bb.getInt(); - this.label = ((mplsheader & 0xfffff000) >> 12); - this.bos = (byte) ((mplsheader & 0x00000100) >> 8); - this.bos = (byte) (mplsheader & 0x000000ff); - this.protocol = (this.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS; - - Deserializer<? extends IPacket> deserializer; - if (protocolDeserializerMap.containsKey(this.protocol)) { - deserializer = protocolDeserializerMap.get(this.protocol); - } else { - deserializer = Data.deserializer(); - } - try { - this.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - - return this; - } - - /** - * Returns the MPLS label. - * - * @return MPLS label - */ - public int getLabel() { - return label; - } - - /** - * Sets the MPLS label. - * - * @param label MPLS label - */ - public void setLabel(int label) { - this.label = label; - } - - /** - * Returns the MPLS TTL of the packet. - * - * @return MPLS TTL of the packet - */ - public byte getTtl() { - return ttl; - } - - /** - * Sets the MPLS TTL of the packet. - * - * @param ttl MPLS TTL - */ - public void setTtl(byte ttl) { - this.ttl = ttl; - } - - /** - * Deserializer function for MPLS packets. - * - * @return deserializer function - */ - public static Deserializer<MPLS> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - MPLS mpls = new MPLS(); - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - int mplsheader = bb.getInt(); - mpls.label = ((mplsheader & 0xfffff000) >>> 12); - mpls.bos = (byte) ((mplsheader & 0x00000100) >> 8); - mpls.ttl = (byte) (mplsheader & 0x000000ff); - mpls.protocol = (mpls.bos == 1) ? PROTOCOL_IPV4 : PROTOCOL_MPLS; - - Deserializer<? extends IPacket> deserializer; - if (protocolDeserializerMap.containsKey(mpls.protocol)) { - deserializer = protocolDeserializerMap.get(mpls.protocol); - } else { - deserializer = Data.deserializer(); - } - mpls.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position()); - mpls.payload.setParent(mpls); - - return mpls; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MacAddress.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MacAddress.java deleted file mode 100644 index cb7f2013..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MacAddress.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.util.Arrays; - -/** - * The class representing MAC address. - */ -public class MacAddress { - - public static final MacAddress NONE = valueOf("a4:23:05:00:00:00"); - public static final MacAddress ZERO = valueOf("00:00:00:00:00:00"); - public static final MacAddress BROADCAST = valueOf("ff:ff:ff:ff:ff:ff"); - - private static final byte[] LL = new byte[]{ - 0x01, (byte) 0x80, (byte) 0xc2, 0x00, 0x00, - 0x00, 0x0e, 0x03 - }; - - public static final int MAC_ADDRESS_LENGTH = 6; - private byte[] address = new byte[MacAddress.MAC_ADDRESS_LENGTH]; - - public MacAddress(final byte[] address) { - this.address = Arrays.copyOf(address, MacAddress.MAC_ADDRESS_LENGTH); - } - - /** - * Returns a MAC address instance representing the value of the specified - * {@code String}. - * - * @param address the String representation of the MAC Address to be parsed. - * @return a MAC Address instance representing the value of the specified - * {@code String}. - * @throws IllegalArgumentException if the string cannot be parsed as a MAC address. - */ - public static MacAddress valueOf(final String address) { - final String[] elements = address.split(":"); - if (elements.length != MacAddress.MAC_ADDRESS_LENGTH) { - throw new IllegalArgumentException( - "Specified MAC Address must contain 12 hex digits" - + " separated pairwise by :'s."); - } - - final byte[] addressInBytes = new byte[MacAddress.MAC_ADDRESS_LENGTH]; - for (int i = 0; i < MacAddress.MAC_ADDRESS_LENGTH; i++) { - final String element = elements[i]; - addressInBytes[i] = (byte) Integer.parseInt(element, 16); - } - - return new MacAddress(addressInBytes); - } - - /** - * Returns a MAC address instance representing the specified {@code byte} - * array. - * - * @param address the byte array to be parsed. - * @return a MAC address instance representing the specified {@code byte} - * array. - * @throws IllegalArgumentException if the byte array cannot be parsed as a MAC address. - */ - public static MacAddress valueOf(final byte[] address) { - if (address.length != MacAddress.MAC_ADDRESS_LENGTH) { - throw new IllegalArgumentException("the length is not " - + MacAddress.MAC_ADDRESS_LENGTH); - } - - return new MacAddress(address); - } - - /** - * Returns a MAC address instance representing the specified {@code long} - * value. The lower 48 bits of the long value are used to parse as a MAC - * address. - * - * @param address the long value to be parsed. The lower 48 bits are used for a - * MAC address. - * @return a MAC address instance representing the specified {@code long} - * value. - * @throws IllegalArgumentException if the long value cannot be parsed as a MAC address. - */ - public static MacAddress valueOf(final long address) { - final byte[] addressInBytes = new byte[]{ - (byte) (address >> 40 & 0xff), (byte) (address >> 32 & 0xff), - (byte) (address >> 24 & 0xff), (byte) (address >> 16 & 0xff), - (byte) (address >> 8 & 0xff), (byte) (address >> 0 & 0xff)}; - - return new MacAddress(addressInBytes); - } - - /** - * Returns the length of the {@code MACAddress}. - * - * @return the length of the {@code MACAddress}. - */ - public int length() { - return this.address.length; - } - - /** - * Returns the value of the {@code MACAddress} as a {@code byte} array. - * - * @return the numeric value represented by this object after conversion to - * type {@code byte} array. - */ - public byte[] toBytes() { - return Arrays.copyOf(this.address, this.address.length); - } - - /** - * Returns the value of the {@code MACAddress} as a {@code long}. - * - * @return the numeric value represented by this object after conversion to - * type {@code long}. - */ - public long toLong() { - long mac = 0; - for (int i = 0; i < 6; i++) { - final long t = (this.address[i] & 0xffL) << (5 - i) * 8; - mac |= t; - } - return mac; - } - - /** - * Returns {@code true} if the MAC address is the broadcast address. - * - * @return {@code true} if the MAC address is the broadcast address. - */ - public boolean isBroadcast() { - for (final byte b : this.address) { - if (b != -1) { - return false; - } - } - return true; - } - - /** - * Returns {@code true} if the MAC address is the multicast address. - * - * @return {@code true} if the MAC address is the multicast address. - */ - public boolean isMulticast() { - if (this.isBroadcast()) { - return false; - } - return (this.address[0] & 0x01) != 0; - } - - /** - * Returns true if this MAC address is link local. - * - * @return true if link local - */ - public boolean isLinkLocal() { - return LL[0] == address[0] && LL[1] == address[1] && LL[2] == address[2] && - LL[3] == address[3] && LL[4] == address[4] && - (LL[5] == address[5] || LL[6] == address[5] || LL[7] == address[5]); - } - - @Override - public boolean equals(final Object o) { - if (o == this) { - return true; - } - - if (!(o instanceof MacAddress)) { - return false; - } - - final MacAddress other = (MacAddress) o; - return Arrays.equals(this.address, other.address); - } - - @Override - public int hashCode() { - return Long.hashCode(toLong()); - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - for (final byte b : this.address) { - if (builder.length() > 0) { - builder.append(":"); - } - builder.append(String.format("%02X", b & 0xFF)); - } - return builder.toString(); - } - - /** - * @return MAC address in string representation without colons (useful for - * radix tree storage) - */ - public String toStringNoColon() { - final StringBuilder builder = new StringBuilder(); - for (final byte b : this.address) { - builder.append(String.format("%02X", b & 0xFF)); - } - return builder.toString(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java deleted file mode 100644 index 09a939fc..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.onlab.packet; - -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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. - */ - -/** - * Representation of a MPLS label. - */ -public class MplsLabel { - - private final int mplsLabel; - - // An MPLS Label maximum 20 bits. - public static final int MAX_MPLS = 0xFFFFF; - - protected MplsLabel(int value) { - this.mplsLabel = value; - } - - public static MplsLabel mplsLabel(int value) { - - if (value < 0 || value > MAX_MPLS) { - String errorMsg = "MPLS label value " + value + - " is not in the interval [0, 0xFFFFF]"; - throw new IllegalArgumentException(errorMsg); - } - return new MplsLabel(value); - } - - public int toInt() { - return this.mplsLabel; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj instanceof MplsLabel) { - - MplsLabel other = (MplsLabel) obj; - - if (this.mplsLabel == other.mplsLabel) { - return true; - } - } - - return false; - } - - @Override - public int hashCode() { - return this.mplsLabel; - } - - @Override - public String toString() { - return String.valueOf(this.mplsLabel); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java deleted file mode 100644 index 5b3902a8..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ONOSLLDP.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import com.google.common.collect.Lists; -import org.apache.commons.lang.ArrayUtils; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; - -/** - * ONOS LLDP containing organizational TLV for ONOS device dicovery. - */ -public class ONOSLLDP extends LLDP { - - public static final byte[] ONLAB_OUI = {(byte) 0xa4, 0x23, 0x05}; - public static final String DEFAULT_DEVICE = "INVALID"; - public static final String DEFAULT_NAME = "ONOS Discovery"; - - public static final byte[] LLDP_NICIRA = {0x01, 0x23, 0x20, 0x00, 0x00, - 0x01}; - public static final byte[] LLDP_MULTICAST = {0x01, (byte) 0x80, - (byte) 0xc2, 0x00, 0x00, 0x0e}; - public static final byte[] BDDP_MULTICAST = {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; - - private static final byte NAME_SUBTYPE = 1; - private static final byte DEVICE_SUBTYPE = 2; - private static final short NAME_LENGTH = 4; //1 for subtype + 3 for OUI - private static final short DEVICE_LENGTH = 4; //1 for subtype + 3 for OUI - private final LLDPOrganizationalTLV nameTLV = new LLDPOrganizationalTLV(); - private final LLDPOrganizationalTLV deviceTLV = new LLDPOrganizationalTLV(); - - // TLV constants: type, size and subtype - // Organizationally specific TLV also have packet offset and contents of TLV - // header - private static final byte CHASSIS_TLV_TYPE = 1; - private static final byte CHASSIS_TLV_SIZE = 7; - private static final byte CHASSIS_TLV_SUBTYPE = 4; - - private static final byte PORT_TLV_TYPE = 2; - private static final byte PORT_TLV_SIZE = 5; - private static final byte PORT_TLV_SUBTYPE = 2; - - private static final byte TTL_TLV_TYPE = 3; - - - private final byte[] ttlValue = new byte[] {0, 0x78}; - - public ONOSLLDP() { - super(); - setName(DEFAULT_NAME); - setDevice(DEFAULT_DEVICE); - setOptionalTLVList(Lists.<LLDPTLV>newArrayList(nameTLV, deviceTLV)); - setTtl(new LLDPTLV().setType(TTL_TLV_TYPE) - .setLength((short) ttlValue.length) - .setValue(ttlValue)); - - } - - private ONOSLLDP(LLDP lldp) { - this.portId = lldp.getPortId(); - this.chassisId = lldp.getChassisId(); - this.ttl = lldp.getTtl(); - this.optionalTLVList = lldp.getOptionalTLVList(); - } - - public void setName(String name) { - nameTLV.setLength((short) (name.length() + NAME_LENGTH)); - nameTLV.setInfoString(name); - nameTLV.setSubType(NAME_SUBTYPE); - nameTLV.setOUI(ONLAB_OUI); - } - - public void setDevice(String device) { - deviceTLV.setInfoString(device); - deviceTLV.setLength((short) (device.length() + DEVICE_LENGTH)); - deviceTLV.setSubType(DEVICE_SUBTYPE); - deviceTLV.setOUI(ONLAB_OUI); - } - - public void setChassisId(final ChassisId chassisId) { - MacAddress chassisMac = MacAddress.valueOf(chassisId.value()); - byte[] chassis = ArrayUtils.addAll(new byte[] {CHASSIS_TLV_SUBTYPE}, - chassisMac.toBytes()); - - LLDPTLV chassisTLV = new LLDPTLV(); - chassisTLV.setLength(CHASSIS_TLV_SIZE); - chassisTLV.setType(CHASSIS_TLV_TYPE); - chassisTLV.setValue(chassis); - this.setChassisId(chassisTLV); - } - - public void setPortId(final int portNumber) { - byte[] port = ArrayUtils.addAll(new byte[] {PORT_TLV_SUBTYPE}, - ByteBuffer.allocate(4).putInt(portNumber).array()); - - LLDPTLV portTLV = new LLDPTLV(); - portTLV.setLength(PORT_TLV_SIZE); - portTLV.setType(PORT_TLV_TYPE); - portTLV.setValue(port); - this.setPortId(portTLV); - } - - public LLDPOrganizationalTLV getNameTLV() { - for (LLDPTLV tlv : this.getOptionalTLVList()) { - if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) { - LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv; - if (orgTLV.getSubType() == NAME_SUBTYPE) { - return orgTLV; - } - } - } - return null; - } - - public LLDPOrganizationalTLV getDeviceTLV() { - for (LLDPTLV tlv : this.getOptionalTLVList()) { - if (tlv.getType() == LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE) { - LLDPOrganizationalTLV orgTLV = (LLDPOrganizationalTLV) tlv; - if (orgTLV.getSubType() == DEVICE_SUBTYPE) { - return orgTLV; - } - } - } - return null; - } - - public String getNameString() { - LLDPOrganizationalTLV tlv = getNameTLV(); - if (tlv != null) { - return new String(tlv.getInfoString(), StandardCharsets.UTF_8); - } - return null; - } - - public String getDeviceString() { - LLDPOrganizationalTLV tlv = getDeviceTLV(); - if (tlv != null) { - return new String(tlv.getInfoString(), StandardCharsets.UTF_8); - } - return null; - } - - public Integer getPort() { - ByteBuffer portBB = ByteBuffer.wrap(this.getPortId().getValue()); - portBB.position(1); - return portBB.getInt(); - } - - /** - * Given an ethernet packet, determines if this is an LLDP from - * ONOS and returns the device the LLDP came from. - * @param eth an ethernet packet - * @return a the lldp packet or null - */ - public static ONOSLLDP parseONOSLLDP(Ethernet eth) { - if (eth.getEtherType() == Ethernet.TYPE_LLDP || - eth.getEtherType() == Ethernet.TYPE_BSN) { - ONOSLLDP onosLldp = new ONOSLLDP((LLDP) eth.getPayload()); //(ONOSLLDP) eth.getPayload(); - if (ONOSLLDP.DEFAULT_NAME.equals(onosLldp.getNameString())) { - return onosLldp; - } - } - return null; - } - - - - - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java deleted file mode 100755 index e6ef0aed..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PIM.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.onlab.packet.pim.PIMHello; -import org.onlab.packet.pim.PIMJoinPrune; - -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements PIM control packet format. - */ -public class PIM extends BasePacket { - - public static final IpAddress PIM_ADDRESS = IpAddress.valueOf("224.0.0.13"); - - public static final byte TYPE_HELLO = 0x00; - public static final byte TYPE_REGISTER = 0x01; - public static final byte TYPE_REGISTER_STOP = 0x02; - public static final byte TYPE_JOIN_PRUNE_REQUEST = 0x03; - public static final byte TYPE_BOOTSTRAP = 0x04; - public static final byte TYPE_ASSERT = 0x05; - public static final byte TYPE_GRAFT = 0x06; - public static final byte TYPE_GRAFT_ACK = 0x07; - public static final byte TYPE_CANDIDATE_RP_ADV = 0x08; - - public static final int PIM_HEADER_LEN = 4; - - public static final byte ADDRESS_FAMILY_IP4 = 0x1; - public static final byte ADDRESS_FAMILY_IP6 = 0x2; - - public static final Map<Byte, Deserializer<? extends IPacket>> PROTOCOL_DESERIALIZER_MAP = - new HashMap<>(); - - static { - PIM.PROTOCOL_DESERIALIZER_MAP.put(PIM.TYPE_HELLO, PIMHello.deserializer()); - PIM.PROTOCOL_DESERIALIZER_MAP.put(PIM.TYPE_JOIN_PRUNE_REQUEST, PIMJoinPrune.deserializer()); - } - - /* - * PIM Header fields - */ - protected byte version; - protected byte type; - protected byte reserved; - protected short checksum; - - /** - * Default constructor. - */ - public PIM() { - super(); - this.version = 2; - this.reserved = 0; - } - - /** - * Return the PIM message type. - * - * @return the pimMsgType - */ - public byte getPimMsgType() { - return this.type; - } - - /** - * Set the PIM message type. Currently PIMJoinPrune and PIMHello are - * supported. - * - * @param type PIM message type - * @return PIM Header - */ - public PIM setPIMType(final byte type) { - this.type = type; - return this; - } - - /** - * Get the version of PIM. - * - * @return the PIM version. Must be 2. - */ - public byte getVersion() { - return version; - } - - /** - * Set the PIM version type. Should not change from 2. - * - * @param version PIM version - */ - public void setVersion(byte version) { - this.version = version; - } - - /** - * Get the reserved field. - * - * @return the reserved field. Must be ignored. - */ - public byte getReserved() { - return reserved; - } - - /** - * Set the reserved field. - * - * @param reserved should be 0 - */ - public void setReserved(byte reserved) { - this.reserved = reserved; - } - - /** - * Get the checksum of this packet. - * - * @return the checksum - */ - public short getChecksum() { - return checksum; - } - - /** - * Set the checksum. - * - * @param checksum the checksum - */ - public void setChecksum(short checksum) { - this.checksum = checksum; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.type; - result = prime * result + this.version; - result = prime * result + this.checksum; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof PIM)) { - return false; - } - final PIM other = (PIM) obj; - if (this.type != other.type) { - return false; - } - if (this.version != other.version) { - return false; - } - if (this.checksum != other.checksum) { - return false; - } - return true; - } - - /** - * Serializes the packet. Will compute and set the following fields if they - * are set to specific values at the time serialize is called: -checksum : 0 - * -length : 0 - * - * @return will return the serialized packet - */ - @Override - public byte[] serialize() { - int length = 4; - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - length += payloadData.length; - } - - final byte[] data = new byte[length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put((byte) ((this.version & 0xf) << 4 | this.type & 0xf)); - bb.put(this.reserved); - bb.putShort(this.checksum); - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof PIM) { - ((PIM) this.parent).setPIMType(TYPE_JOIN_PRUNE_REQUEST); - } - - // compute checksum if needed - if (this.checksum == 0) { - bb.rewind(); - int accumulation = 0; - - for (int i = 0; i < length / 2; ++i) { - accumulation += 0xffff & bb.getShort(); - } - // pad to an even number of shorts - if (length % 2 > 0) { - accumulation += (bb.get() & 0xff) << 8; - } - - accumulation = (accumulation >> 16 & 0xffff) - + (accumulation & 0xffff); - this.checksum = (short) (~accumulation & 0xffff); - bb.putShort(2, this.checksum); - } - return data; - } - - /** - * Deserialize the PIM packet. - * - * @param data bytes to deserialize. - * @param offset offset to start deserializing from - * @param length length of the data to deserialize - * - * @return the deserialized PIM packet. - */ - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.type = bb.get(); - this.version = bb.get(); - this.checksum = bb.getShort(); - - //this.payload = new Data(); - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() - bb.position()); - this.payload.setParent(this); - return this; - } - /** - * Deserializer function for IPv4 packets. - * - * @return deserializer function - */ - public static Deserializer<PIM> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, PIM_HEADER_LEN); - - PIM pim = new PIM(); - - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - byte versionByte = bb.get(); - pim.version = (byte) (versionByte >> 4 & 0xf); - pim.setPIMType((byte) (versionByte & 0xf)); - pim.reserved = bb.get(); - pim.checksum = bb.getShort(); - - Deserializer<? extends IPacket> deserializer; - if (PIM.PROTOCOL_DESERIALIZER_MAP.containsKey(pim.getPimMsgType())) { - deserializer = PIM.PROTOCOL_DESERIALIZER_MAP.get(pim.getPimMsgType()); - } else { - deserializer = Data.deserializer(); - } - - pim.payload = deserializer.deserialize(data, bb.position(), bb.limit() - bb.position()); - pim.payload.setParent(pim); - - return pim; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PacketUtils.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PacketUtils.java deleted file mode 100644 index c3bede2f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/PacketUtils.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Utilities for working with packet headers. - */ -public final class PacketUtils { - - private PacketUtils() { - } - - /** - * Check the length of the input buffer is appropriate given the offset and - * length parameters. - * - * @param byteLength length of the input buffer array - * @param offset offset given to begin reading bytes from - * @param length length given to read up until - * @throws DeserializationException if the input parameters don't match up (i.e - * we can't read that many bytes from the buffer at the given offest) - */ - public static void checkBufferLength(int byteLength, int offset, int length) - throws DeserializationException { - boolean ok = (offset >= 0 && offset < byteLength); - ok = ok & (length >= 0 && offset + length <= byteLength); - - if (!ok) { - throw new DeserializationException("Unable to read " + length + " bytes from a " - + byteLength + " byte array starting at offset " + offset); - } - } - - /** - * Check that there are enough bytes in the buffer to read some number of - * bytes that we need to read a full header. - * - * @param givenLength given size of the buffer - * @param requiredLength number of bytes we need to read some header fully - * @throws DeserializationException if there aren't enough bytes - */ - public static void checkHeaderLength(int givenLength, int requiredLength) - throws DeserializationException { - if (requiredLength > givenLength) { - throw new DeserializationException(requiredLength - + " bytes are needed to continue deserialization, however only " - + givenLength + " remain in buffer"); - } - } - - /** - * Check the input parameters are sane and there's enough bytes to read - * the required length. - * - * @param data input byte buffer - * @param offset offset of the start of the header - * @param length length given to deserialize the header - * @param requiredLength length needed to deserialize header - * @throws DeserializationException if we're unable to deserialize the - * packet based on the input parameters - */ - public static void checkInput(byte[] data, int offset, int length, int requiredLength) - throws DeserializationException { - checkNotNull(data); - checkBufferLength(data.length, offset, length); - checkHeaderLength(length, requiredLength); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/RADIUS.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/RADIUS.java deleted file mode 100644 index 297fee7c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/RADIUS.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * - * * Copyright 2015 AT&T Foundry - * * - * * 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.onlab.packet; - -import org.slf4j.Logger; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.onlab.packet.PacketUtils.checkHeaderLength; -import static org.onlab.packet.PacketUtils.checkInput; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * RADIUS packet. - */ -public class RADIUS extends BasePacket { - protected byte code; - protected byte identifier; - protected short length = RADIUS_MIN_LENGTH; - protected byte[] authenticator = new byte[16]; - protected List<RADIUSAttribute> attributes = new ArrayList<>(); - - // RADIUS parameters - public static final short RADIUS_MIN_LENGTH = 20; - public static final short MAX_ATTR_VALUE_LENGTH = 253; - public static final short RADIUS_MAX_LENGTH = 4096; - - // RADIUS packet types - public static final byte RADIUS_CODE_ACCESS_REQUEST = 0x01; - public static final byte RADIUS_CODE_ACCESS_ACCEPT = 0x02; - public static final byte RADIUS_CODE_ACCESS_REJECT = 0x03; - public static final byte RADIUS_CODE_ACCOUNTING_REQUEST = 0x04; - public static final byte RADIUS_CODE_ACCOUNTING_RESPONSE = 0x05; - public static final byte RADIUS_CODE_ACCESS_CHALLENGE = 0x0b; - - private final Logger log = getLogger(getClass()); - - /** - * Default constructor. - */ - public RADIUS() { - } - - /** - * Constructs a RADIUS packet with the given code and identifier. - * - * @param code code - * @param identifier identifier - */ - public RADIUS(byte code, byte identifier) { - this.code = code; - this.identifier = identifier; - } - - /** - * Gets the code. - * - * @return code - */ - public byte getCode() { - return this.code; - } - - /** - * Sets the code. - * - * @param code code - */ - public void setCode(byte code) { - this.code = code; - } - - /** - * Gets the identifier. - * - * @return identifier - */ - public byte getIdentifier() { - return this.identifier; - } - - /** - * Sets the identifier. - * - * @param identifier identifier - */ - public void setIdentifier(byte identifier) { - this.identifier = identifier; - } - - /** - * Gets the authenticator. - * - * @return authenticator - */ - public byte[] getAuthenticator() { - return this.authenticator; - } - - /** - * Sets the authenticator. - * - * @param authenticator authenticator - */ - public void setAuthenticator(byte[] authenticator) { - this.authenticator = authenticator; - } - - /** - * Generates an authenticator code. - * - * @return the authenticator - */ - public byte[] generateAuthCode() { - new SecureRandom().nextBytes(this.authenticator); - return this.authenticator; - } - - /** - * Checks if the packet's code field is valid. - * - * @return whether the code is valid - */ - public boolean isValidCode() { - return this.code == RADIUS_CODE_ACCESS_REQUEST || - this.code == RADIUS_CODE_ACCESS_ACCEPT || - this.code == RADIUS_CODE_ACCESS_REJECT || - this.code == RADIUS_CODE_ACCOUNTING_REQUEST || - this.code == RADIUS_CODE_ACCOUNTING_RESPONSE || - this.code == RADIUS_CODE_ACCESS_CHALLENGE; - } - - /** - * Adds a message authenticator to the packet based on the given key. - * - * @param key key to generate message authenticator - * @return the messgae authenticator RADIUS attribute - */ - public RADIUSAttribute addMessageAuthenticator(String key) { - // Message-Authenticator = HMAC-MD5 (Type, Identifier, Length, - // Request Authenticator, Attributes) - // When the message integrity check is calculated the signature string - // should be considered to be sixteen octets of zero. - byte[] hashOutput = new byte[16]; - Arrays.fill(hashOutput, (byte) 0); - - RADIUSAttribute authAttribute = this.getAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH); - if (authAttribute != null) { - // If Message-Authenticator was already present, override it - this.log.warn("Attempted to add duplicate Message-Authenticator"); - authAttribute = this.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, hashOutput); - } else { - // Else generate a new attribute padded with zeroes - authAttribute = this.setAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, hashOutput); - } - // Calculate the MD5 HMAC based on the message - try { - SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacMD5"); - Mac mac = Mac.getInstance("HmacMD5"); - mac.init(keySpec); - hashOutput = mac.doFinal(this.serialize()); - // Update HMAC in Message-Authenticator - authAttribute = this.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, hashOutput); - } catch (Exception e) { - this.log.error("Failed to generate message authenticator: {}", e.getMessage()); - } - - return authAttribute; - } - - /** - * Checks the message authenticator in the packet with one generated from - * the given key. - * - * @param key key to generate message authenticator - * @return whether the message authenticators match or not - */ - public boolean checkMessageAuthenticator(String key) { - byte[] newHash = new byte[16]; - Arrays.fill(newHash, (byte) 0); - byte[] messageAuthenticator = this.getAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH).getValue(); - this.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, newHash); - // Calculate the MD5 HMAC based on the message - try { - SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacMD5"); - Mac mac = Mac.getInstance("HmacMD5"); - mac.init(keySpec); - newHash = mac.doFinal(this.serialize()); - } catch (Exception e) { - log.error("Failed to generate message authenticator: {}", e.getMessage()); - } - this.updateAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, messageAuthenticator); - // Compare the calculated Message-Authenticator with the one in the message - return Arrays.equals(newHash, messageAuthenticator); - } - - /** - * Encapsulates an EAP packet in this RADIUS packet. - * - * @param message EAP message object to be embedded in the RADIUS - * EAP-Message attributed - */ - public void encapsulateMessage(EAP message) { - if (message.length <= MAX_ATTR_VALUE_LENGTH) { - // Use the regular serialization method as it fits into one EAP-Message attribute - this.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE, - message.serialize()); - } else { - // Segment the message into chucks and embed them in several EAP-Message attributes - short remainingLength = message.length; - byte[] messageBuffer = message.serialize(); - final ByteBuffer bb = ByteBuffer.wrap(messageBuffer); - while (bb.hasRemaining()) { - byte[] messageAttributeData; - if (remainingLength > MAX_ATTR_VALUE_LENGTH) { - // The remaining data is still too long to fit into one attribute, keep going - messageAttributeData = new byte[MAX_ATTR_VALUE_LENGTH]; - bb.get(messageAttributeData, 0, MAX_ATTR_VALUE_LENGTH); - remainingLength -= MAX_ATTR_VALUE_LENGTH; - } else { - // The remaining data fits, this will be the last chunk - messageAttributeData = new byte[remainingLength]; - bb.get(messageAttributeData, 0, remainingLength); - } - this.attributes.add(new RADIUSAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE, - (byte) (messageAttributeData.length + 2), messageAttributeData)); - - // Adding the size of the data to the total RADIUS length - this.length += (short) (messageAttributeData.length & 0xFF); - // Adding the size of the overhead attribute type and length - this.length += 2; - } - } - } - - /** - * Decapsulates an EAP packet from the RADIUS packet. - * - * @return An EAP object containing the reassembled EAP message - */ - public EAP decapsulateMessage() { - EAP message = new EAP(); - ByteArrayOutputStream messageStream = new ByteArrayOutputStream(); - // Iterating through EAP-Message attributes to concatenate their value - for (RADIUSAttribute ra : this.getAttributeList(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE)) { - try { - messageStream.write(ra.getValue()); - } catch (IOException e) { - log.error("Error while reassembling EAP message: {}", e.getMessage()); - } - } - // Assembling EAP object from the concatenated stream - message.deserialize(messageStream.toByteArray(), 0, messageStream.size()); - return message; - } - - /** - * Gets a list of attributes from the RADIUS packet. - * - * @param attrType the type field of the required attributes - * @return List of the attributes that matches the type or an empty list if there is none - */ - public ArrayList<RADIUSAttribute> getAttributeList(byte attrType) { - ArrayList<RADIUSAttribute> attrList = new ArrayList<>(); - for (int i = 0; i < this.attributes.size(); i++) { - if (this.attributes.get(i).getType() == attrType) { - attrList.add(this.attributes.get(i)); - } - } - return attrList; - } - - /** - * Gets an attribute from the RADIUS packet. - * - * @param attrType the type field of the required attribute - * @return the first attribute that matches the type or null if does not exist - */ - public RADIUSAttribute getAttribute(byte attrType) { - for (int i = 0; i < this.attributes.size(); i++) { - if (this.attributes.get(i).getType() == attrType) { - return this.attributes.get(i); - } - } - return null; - } - - /** - * Sets an attribute in the RADIUS packet. - * - * @param attrType the type field of the attribute to set - * @param value value to be set - * @return reference to the attribute object - */ - public RADIUSAttribute setAttribute(byte attrType, byte[] value) { - byte attrLength = (byte) (value.length + 2); - RADIUSAttribute newAttribute = new RADIUSAttribute(attrType, attrLength, value); - this.attributes.add(newAttribute); - this.length += (short) (attrLength & 0xFF); - return newAttribute; - } - - /** - * Updates an attribute in the RADIUS packet. - * - * @param attrType the type field of the attribute to update - * @param value the value to update to - * @return reference to the attribute object - */ - public RADIUSAttribute updateAttribute(byte attrType, byte[] value) { - for (int i = 0; i < this.attributes.size(); i++) { - if (this.attributes.get(i).getType() == attrType) { - this.length -= (short) (this.attributes.get(i).getLength() & 0xFF); - RADIUSAttribute newAttr = new RADIUSAttribute(attrType, (byte) (value.length + 2), value); - this.attributes.set(i, newAttr); - this.length += (short) (newAttr.getLength() & 0xFF); - return newAttr; - } - } - return null; - } - - /** - * Deserializer for RADIUS packets. - * - * @return deserializer - */ - public static Deserializer<RADIUS> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, RADIUS_MIN_LENGTH); - - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - RADIUS radius = new RADIUS(); - radius.code = bb.get(); - radius.identifier = bb.get(); - radius.length = bb.getShort(); - bb.get(radius.authenticator, 0, 16); - - checkHeaderLength(length, radius.length); - - int remainingLength = radius.length - RADIUS_MIN_LENGTH; - while (remainingLength > 0 && bb.hasRemaining()) { - - RADIUSAttribute attr = new RADIUSAttribute(); - attr.setType(bb.get()); - attr.setLength(bb.get()); - short attrLength = (short) (attr.length & 0xff); - attr.value = new byte[attrLength - 2]; - bb.get(attr.value, 0, attrLength - 2); - radius.attributes.add(attr); - remainingLength -= attr.length; - } - return radius; - }; - } - - @Override - public byte[] serialize() { - final byte[] data = new byte[this.length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.code); - bb.put(this.identifier); - bb.putShort(this.length); - bb.put(this.authenticator); - for (int i = 0; i < this.attributes.size(); i++) { - RADIUSAttribute attr = this.attributes.get(i); - bb.put(attr.getType()); - bb.put(attr.getLength()); - bb.put(attr.getValue()); - } - - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.code = bb.get(); - this.identifier = bb.get(); - this.length = bb.getShort(); - bb.get(this.authenticator, 0, 16); - - int remainingLength = this.length - RADIUS_MIN_LENGTH; - while (remainingLength > 0 && bb.hasRemaining()) { - RADIUSAttribute attr = new RADIUSAttribute(); - attr.setType(bb.get()); - attr.setLength(bb.get()); - short attrLength = (short) (attr.length & 0xff); - attr.value = new byte[attrLength - 2]; - bb.get(attr.value, 0, attrLength - 2); - this.attributes.add(attr); - remainingLength -= attr.length; - } - return this; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/RADIUSAttribute.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/RADIUSAttribute.java deleted file mode 100644 index 9687e377..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/RADIUSAttribute.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * - * * Copyright 2015 AT&T Foundry - * * - * * 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.onlab.packet; - -/** - * An attribute in a RADIUS packet. - */ -public class RADIUSAttribute { - protected byte type; - protected byte length; - protected byte[] value; - - // RADIUS attribute types - public static final byte RADIUS_ATTR_USERNAME = 1; - public static final byte RADIUS_ATTR_NAS_IP = 4; - public static final byte RADIUS_ATTR_NAS_PORT = 5; - public static final byte RADIUS_ATTR_FRAMED_MTU = 12; - public static final byte RADIUS_ATTR_STATE = 24; - public static final byte RADIUS_ATTR_VENDOR_SPECIFIC = 26; - public static final byte RADIUS_ATTR_CALLING_STATION_ID = 31; - public static final byte RADIUS_ATTR_NAS_ID = 32; - public static final byte RADIUS_ATTR_ACCT_SESSION_ID = 44; - public static final byte RADIUS_ATTR_NAS_PORT_TYPE = 61; - public static final byte RADIUS_ATTR_EAP_MESSAGE = 79; - public static final byte RADIUS_ATTR_MESSAGE_AUTH = 80; - public static final byte RADIUS_ATTR_NAS_PORT_ID = 87; - - /** - * Default constructor. - */ - public RADIUSAttribute() { - } - - /** - * Constructs a RADIUS attribute with the give type, length and value. - * - * @param type type - * @param length length - * @param value value - */ - public RADIUSAttribute(final byte type, final byte length, final byte[] value) { - this.type = type; - this.length = length; - this.value = value; - } - - /** - * Checks if the attribute type is valid. - * - * @return whether the type is valid or not - */ - public boolean isValidType() { - return this.type == RADIUS_ATTR_USERNAME || - this.type == RADIUS_ATTR_NAS_IP || - this.type == RADIUS_ATTR_NAS_PORT || - this.type == RADIUS_ATTR_VENDOR_SPECIFIC || - this.type == RADIUS_ATTR_CALLING_STATION_ID || - this.type == RADIUS_ATTR_NAS_ID || - this.type == RADIUS_ATTR_ACCT_SESSION_ID || - this.type == RADIUS_ATTR_NAS_PORT_TYPE || - this.type == RADIUS_ATTR_EAP_MESSAGE || - this.type == RADIUS_ATTR_MESSAGE_AUTH || - this.type == RADIUS_ATTR_NAS_PORT_ID; - } - - /** - * Gets the attribute type. - * - * @return the type - */ - public byte getType() { - return this.type; - } - - /** - * Sets the attribute type. - * - * @param type the code to set - * @return this - */ - public RADIUSAttribute setType(final byte type) { - this.type = type; - return this; - } - - /** - * Gets the attribute length. - * - * @return the length - */ - public byte getLength() { - return this.length; - } - - /** - * Sets the attribute length. - * - * @param length the length to set - * @return this - */ - public RADIUSAttribute setLength(final byte length) { - this.length = length; - return this; - } - - /** - * Gets the attribute value. - * - * @return the value - */ - public byte[] getValue() { - return this.value; - } - - /** - * Sets the attribute value. - * - * @param value the data to set - * @return this - */ - public RADIUSAttribute setValue(final byte[] value) { - this.value = value; - return this; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/TCP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/TCP.java deleted file mode 100644 index e089f272..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/TCP.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import static org.onlab.packet.PacketUtils.*; - -/** - * Implements TCP packet format. - */ - -public class TCP extends BasePacket { - - private static final short TCP_HEADER_LENGTH = 20; - - protected int sourcePort; - protected int destinationPort; - protected int sequence; - protected int acknowledge; - protected byte dataOffset; - protected short flags; - protected short windowSize; - protected short checksum; - protected short urgentPointer; - protected byte[] options; - - /** - * Gets TCP source port. - * - * @return TCP source port - */ - public int getSourcePort() { - return this.sourcePort; - } - - /** - * Sets TCP source port. - * - * @param sourcePort the sourcePort to set (unsigned 16 bits integer) - * @return this - */ - public TCP setSourcePort(final int sourcePort) { - this.sourcePort = sourcePort; - return this; - } - - /** - * Gets TCP destination port. - * - * @return the destinationPort - */ - public int getDestinationPort() { - return this.destinationPort; - } - - /** - * Sets TCP destination port. - * - * @param destinationPort the destinationPort to set (unsigned 16 bits integer) - * @return this - */ - public TCP setDestinationPort(final int destinationPort) { - this.destinationPort = destinationPort; - return this; - } - - /** - * Gets checksum. - * - * @return the checksum - */ - public short getChecksum() { - return this.checksum; - } - - /** - * Sets checksum. - * - * @param checksum the checksum to set - * @return this - */ - public TCP setChecksum(final short checksum) { - this.checksum = checksum; - return this; - } - - /** - * Gets sequence number. - * - * @return the sequence number - */ - public int getSequence() { - return this.sequence; - } - - /** - * Sets sequence number. - * - * @param seq the sequence number to set - * @return this - */ - public TCP setSequence(final int seq) { - this.sequence = seq; - return this; - } - - /** - * Gets acknowledge number. - * - * @return the acknowledge number - */ - public int getAcknowledge() { - return this.acknowledge; - } - - /** - * Sets acknowledge number. - * - * @param ack the acknowledge number to set - * @return this - */ - public TCP setAcknowledge(final int ack) { - this.acknowledge = ack; - return this; - } - - /** - * Gets offset. - * - * @return the offset - */ - public byte getDataOffset() { - return this.dataOffset; - } - - /** - * Sets offset. - * - * @param offset the offset to set - * @return this - */ - public TCP setDataOffset(final byte offset) { - this.dataOffset = offset; - return this; - } - - /** - * Gets TCP flags. - * - * @return the TCP flags - */ - public short getFlags() { - return this.flags; - } - - /** - * Sets TCP flags. - * - * @param flags the TCP flags to set - * @return this - */ - public TCP setFlags(final short flags) { - this.flags = flags; - return this; - } - - /** - * Gets TCP window size. - * - * @return the TCP window size - */ - public short getWindowSize() { - return this.windowSize; - } - - /** - * Sets TCP window size. - * - * @param windowSize the TCP window size to set - * @return this - */ - public TCP setWindowSize(final short windowSize) { - this.windowSize = windowSize; - return this; - } - - @Override - public void resetChecksum() { - this.checksum = 0; - super.resetChecksum(); - } - - /** - * Gets urgent pointer. - * - * @return the urgent pointer - */ - public short getUrgentPointer() { - return this.urgentPointer; - } - - /** - * Sets urgent pointer. - * - * @param urgentPointer the urgent pointer to set - * @return this - */ - public TCP setUrgentPointer(final short urgentPointer) { - this.urgentPointer = urgentPointer; - return this; - } - - /** - * Gets TCP options. - * - * @return the TCP options - */ - public byte[] getOptions() { - return this.options; - } - - /** - * Sets TCP options. - * - * @param options the options to set - * @return this - */ - public TCP setOptions(final byte[] options) { - this.options = options; - this.dataOffset = (byte) (20 + options.length + 3 >> 2); - return this; - } - - /** - * Serializes the packet. Will compute and set the following fields if they - * are set to specific values at the time serialize is called: -checksum : 0 - * -length : 0 - */ - @Override - public byte[] serialize() { - int length; - if (this.dataOffset == 0) { - this.dataOffset = 5; // default header length - } - length = this.dataOffset << 2; - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - length += payloadData.length; - } - - final byte[] data = new byte[length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putShort((short) (this.sourcePort & 0xffff)); - bb.putShort((short) (this.destinationPort & 0xffff)); - bb.putInt(this.sequence); - bb.putInt(this.acknowledge); - bb.putShort((short) (this.flags | this.dataOffset << 12)); - bb.putShort(this.windowSize); - bb.putShort(this.checksum); - bb.putShort(this.urgentPointer); - if (this.dataOffset > 5) { - int padding; - bb.put(this.options); - padding = (this.dataOffset << 2) - 20 - this.options.length; - for (int i = 0; i < padding; i++) { - bb.put((byte) 0); - } - } - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof IPv4) { - ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_TCP); - } - - // compute checksum if needed - if (this.checksum == 0) { - bb.rewind(); - int accumulation = 0; - - // compute pseudo header mac - if (this.parent != null) { - if (this.parent instanceof IPv4) { - final IPv4 ipv4 = (IPv4) this.parent; - accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff) - + (ipv4.getSourceAddress() & 0xffff); - accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff) - + (ipv4.getDestinationAddress() & 0xffff); - accumulation += ipv4.getProtocol() & 0xff; - accumulation += length & 0xffff; - } else if (this.parent instanceof IPv6) { - final IPv6 ipv6 = (IPv6) this.parent; - final int bbLength = - Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst - + 2 // nextHeader (with padding) - + 4; // length - final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength); - bbChecksum.put(ipv6.getSourceAddress()); - bbChecksum.put(ipv6.getDestinationAddress()); - bbChecksum.put((byte) 0); // padding - bbChecksum.put(ipv6.getNextHeader()); - bbChecksum.putInt(length); - bbChecksum.rewind(); - for (int i = 0; i < bbLength / 2; ++i) { - accumulation += 0xffff & bbChecksum.getShort(); - } - } - } - - for (int i = 0; i < length / 2; ++i) { - accumulation += 0xffff & bb.getShort(); - } - // pad to an even number of shorts - if (length % 2 > 0) { - accumulation += (bb.get() & 0xff) << 8; - } - - accumulation = (accumulation >> 16 & 0xffff) - + (accumulation & 0xffff); - this.checksum = (short) (~accumulation & 0xffff); - bb.putShort(16, this.checksum); - } - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.sourcePort = (bb.getShort() & 0xffff); - this.destinationPort = (bb.getShort() & 0xffff); - this.sequence = bb.getInt(); - this.acknowledge = bb.getInt(); - this.flags = bb.getShort(); - this.dataOffset = (byte) (this.flags >> 12 & 0xf); - this.flags = (short) (this.flags & 0x1ff); - this.windowSize = bb.getShort(); - this.checksum = bb.getShort(); - this.urgentPointer = bb.getShort(); - if (this.dataOffset > 5) { - int optLength = (this.dataOffset << 2) - 20; - if (bb.limit() < bb.position() + optLength) { - optLength = bb.limit() - bb.position(); - } - try { - this.options = new byte[optLength]; - bb.get(this.options, 0, optLength); - } catch (final IndexOutOfBoundsException e) { - this.options = null; - } - } - - this.payload = new Data(); - this.payload = this.payload.deserialize(data, bb.position(), bb.limit() - - bb.position()); - this.payload.setParent(this); - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.checksum; - result = prime * result + this.destinationPort; - result = prime * result + this.sourcePort; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof TCP)) { - return false; - } - final TCP other = (TCP) obj; - // May want to compare fields based on the flags set - return this.checksum == other.checksum - && this.destinationPort == other.destinationPort - && this.sourcePort == other.sourcePort - && this.sequence == other.sequence - && this.acknowledge == other.acknowledge - && this.dataOffset == other.dataOffset - && this.flags == other.flags - && this.windowSize == other.windowSize - && this.urgentPointer == other.urgentPointer - && (this.dataOffset == 5 || Arrays.equals(this.options, other.options)); - } - - /** - * Deserializer function for TCP packets. - * - * @return deserializer function - */ - public static Deserializer<TCP> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, TCP_HEADER_LENGTH); - - TCP tcp = new TCP(); - - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - tcp.sourcePort = (bb.getShort() & 0xffff); - tcp.destinationPort = (bb.getShort() & 0xffff); - tcp.sequence = bb.getInt(); - tcp.acknowledge = bb.getInt(); - tcp.flags = bb.getShort(); - tcp.dataOffset = (byte) (tcp.flags >> 12 & 0xf); - tcp.flags = (short) (tcp.flags & 0x1ff); - tcp.windowSize = bb.getShort(); - tcp.checksum = bb.getShort(); - tcp.urgentPointer = bb.getShort(); - if (tcp.dataOffset > 5) { - int optLength = (tcp.dataOffset << 2) - 20; - checkHeaderLength(length, TCP_HEADER_LENGTH + tcp.dataOffset); - tcp.options = new byte[optLength]; - bb.get(tcp.options, 0, optLength); - } - - tcp.payload = Data.deserializer() - .deserialize(data, bb.position(), bb.limit() - bb.position()); - tcp.payload.setParent(tcp); - return tcp; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/TpPort.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/TpPort.java deleted file mode 100644 index 9b86a816..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/TpPort.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.onlab.packet; - -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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. - */ - -/** - * Representation of a transport layer port. - */ -public class TpPort { - - private final int port; - - // Transport layer port is unsigned 16 bits integer. - public static final int MAX_PORT = 0xFFFF; - public static final int MIN_PORT = 0; - - /** - * Constructs a new TpPort. - * - * @param value the transport layer port - */ - protected TpPort(int value) { - this.port = value; - } - - /** - * Converts an integer into a TpPort. - * - * @param value an integer representing the transport layer port - * @return a TpPort - * @throws IllegalArgumentException if the value is invalid - */ - public static TpPort tpPort(int value) { - if (value < MIN_PORT || value > MAX_PORT) { - throw new IllegalArgumentException( - "Transport layer port value " + value + "is not in the interval [0, 0xFFFF]"); - } - return new TpPort(value); - } - - /** - * Returns the integer value for this transport port. - * - * @return an integer value - */ - public int toInt() { - return this.port; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj instanceof TpPort) { - - TpPort other = (TpPort) obj; - - if (this.port == other.port) { - return true; - } - } - return false; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return this.port; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return String.valueOf(this.port); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/UDP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/UDP.java deleted file mode 100644 index a30c9a92..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/UDP.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; - -import static org.onlab.packet.PacketUtils.*; - -/** - * Representation of a UDP packet. - */ -public class UDP extends BasePacket { - public static final Map<Integer, Deserializer<? extends IPacket>> PORT_DESERIALIZER_MAP = - new HashMap<>(); - public static final int DHCP_SERVER_PORT = 67; - public static final int DHCP_CLIENT_PORT = 68; - - private static final short UDP_HEADER_LENGTH = 8; - - static { - /* - * Disable DHCP until the deserialize code is hardened to deal with - * garbage input - */ - UDP.PORT_DESERIALIZER_MAP.put(UDP.DHCP_SERVER_PORT, DHCP.deserializer()); - UDP.PORT_DESERIALIZER_MAP.put(UDP.DHCP_CLIENT_PORT, DHCP.deserializer()); - - } - - protected int sourcePort; - protected int destinationPort; - protected short length; - protected short checksum; - - /** - * @return the sourcePort - */ - public int getSourcePort() { - return this.sourcePort; - } - - /** - * @param sourcePort - * the sourcePort to set (16 bits unsigned integer) - * @return this - */ - public UDP setSourcePort(final int sourcePort) { - this.sourcePort = sourcePort; - return this; - } - - /** - * @return the destinationPort - */ - public int getDestinationPort() { - return this.destinationPort; - } - - /** - * @param destinationPort - * the destinationPort to set (16 bits unsigned integer) - * @return this - */ - public UDP setDestinationPort(final int destinationPort) { - this.destinationPort = destinationPort; - return this; - } - - /** - * @return the length - */ - public short getLength() { - return this.length; - } - - /** - * @return the checksum - */ - public short getChecksum() { - return this.checksum; - } - - /** - * @param checksum - * the checksum to set - * @return this - */ - public UDP setChecksum(final short checksum) { - this.checksum = checksum; - return this; - } - - @Override - public void resetChecksum() { - this.checksum = 0; - super.resetChecksum(); - } - - /** - * Serializes the packet. Will compute and set the following fields if they - * are set to specific values at the time serialize is called: -checksum : 0 - * -length : 0 - */ - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - this.length = (short) (8 + (payloadData == null ? 0 - : payloadData.length)); - - final byte[] data = new byte[this.length]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putShort((short) (this.sourcePort & 0xffff)); - bb.putShort((short) (this.destinationPort & 0xffff)); - bb.putShort(this.length); - bb.putShort(this.checksum); - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof IPv4) { - ((IPv4) this.parent).setProtocol(IPv4.PROTOCOL_UDP); - } - - // compute checksum if needed - if (this.checksum == 0) { - bb.rewind(); - int accumulation = 0; - - // compute pseudo header mac - if (this.parent != null) { - if (this.parent instanceof IPv4) { - final IPv4 ipv4 = (IPv4) this.parent; - accumulation += (ipv4.getSourceAddress() >> 16 & 0xffff) - + (ipv4.getSourceAddress() & 0xffff); - accumulation += (ipv4.getDestinationAddress() >> 16 & 0xffff) - + (ipv4.getDestinationAddress() & 0xffff); - accumulation += ipv4.getProtocol() & 0xff; - accumulation += length & 0xffff; - } else if (this.parent instanceof IPv6) { - final IPv6 ipv6 = (IPv6) this.parent; - final int bbLength = - Ip6Address.BYTE_LENGTH * 2 // IPv6 src, dst - + 2 // nextHeader (with padding) - + 4; // length - final ByteBuffer bbChecksum = ByteBuffer.allocate(bbLength); - bbChecksum.put(ipv6.getSourceAddress()); - bbChecksum.put(ipv6.getDestinationAddress()); - bbChecksum.put((byte) 0); // padding - bbChecksum.put(ipv6.getNextHeader()); - bbChecksum.putInt(length); - bbChecksum.rewind(); - for (int i = 0; i < bbLength / 2; ++i) { - accumulation += 0xffff & bbChecksum.getShort(); - } - } - } - - for (int i = 0; i < this.length / 2; ++i) { - accumulation += 0xffff & bb.getShort(); - } - // pad to an even number of shorts - if (this.length % 2 > 0) { - accumulation += (bb.get() & 0xff) << 8; - } - - accumulation = (accumulation >> 16 & 0xffff) - + (accumulation & 0xffff); - this.checksum = (short) (~accumulation & 0xffff); - bb.putShort(6, this.checksum); - } - return data; - } - - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.sourcePort = (bb.getShort() & 0xffff); - this.destinationPort = (bb.getShort() & 0xffff); - this.length = bb.getShort(); - this.checksum = bb.getShort(); - - Deserializer<? extends IPacket> deserializer; - if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.destinationPort)) { - deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.destinationPort); - } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(this.sourcePort)) { - deserializer = UDP.PORT_DESERIALIZER_MAP.get(this.sourcePort); - } else { - deserializer = Data.deserializer(); - } - - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.checksum; - result = prime * result + this.destinationPort; - result = prime * result + this.length; - result = prime * result + this.sourcePort; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof UDP)) { - return false; - } - final UDP other = (UDP) obj; - if (this.checksum != other.checksum) { - return false; - } - if (this.destinationPort != other.destinationPort) { - return false; - } - if (this.length != other.length) { - return false; - } - if (this.sourcePort != other.sourcePort) { - return false; - } - return true; - } - - /** - * Deserializer function for UDP packets. - * - * @return deserializer function - */ - public static Deserializer<UDP> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, UDP_HEADER_LENGTH); - - UDP udp = new UDP(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - udp.sourcePort = (bb.getShort() & 0xffff); - udp.destinationPort = (bb.getShort() & 0xffff); - udp.length = bb.getShort(); - udp.checksum = bb.getShort(); - - Deserializer<? extends IPacket> deserializer; - if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.destinationPort)) { - deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.destinationPort); - } else if (UDP.PORT_DESERIALIZER_MAP.containsKey(udp.sourcePort)) { - deserializer = UDP.PORT_DESERIALIZER_MAP.get(udp.sourcePort); - } else { - deserializer = Data.deserializer(); - } - - udp.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - udp.payload.setParent(udp); - return udp; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/VlanId.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/VlanId.java deleted file mode 100644 index 4b38308b..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/VlanId.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -/** - * Representation of a VLAN ID. - */ -public class VlanId { - - private final short value; - - // Based on convention used elsewhere? Check and change if needed - public static final short UNTAGGED = (short) 0xffff; - - // In a traffic selector, this means that a VLAN ID must be present, but - // can have any value. We use the same value as OpenFlow, but this is not - // required. - public static final short ANY_VALUE = (short) 0x1000; - - public static final VlanId NONE = VlanId.vlanId(UNTAGGED); - public static final VlanId ANY = VlanId.vlanId(ANY_VALUE); - - // A VLAN ID is actually 12 bits of a VLAN tag. - public static final short MAX_VLAN = 4095; - - protected VlanId() { - this.value = UNTAGGED; - } - - protected VlanId(short value) { - this.value = value; - } - - public static VlanId vlanId() { - return new VlanId(UNTAGGED); - } - - public static VlanId vlanId(short value) { - if (value == UNTAGGED) { - return new VlanId(); - } - - if (value == ANY_VALUE) { - return new VlanId(ANY_VALUE); - } - - if (value > MAX_VLAN) { - throw new IllegalArgumentException( - "value exceeds allowed maximum VLAN ID value (4095)"); - } - return new VlanId(value); - } - - public short toShort() { - return this.value; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj instanceof VlanId) { - - VlanId other = (VlanId) obj; - - if (this.value == other.value) { - return true; - } - } - - return false; - } - - @Override - public int hashCode() { - return this.value; - } - - @Override - public String toString() { - if (this.value == ANY_VALUE) { - return "Any"; - } - return String.valueOf(this.value); - } -} - diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Authentication.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Authentication.java deleted file mode 100644 index ec04a812..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Authentication.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Data; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.IPv6; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements IPv6 authentication extension header format. (RFC 4302) - */ -public class Authentication extends BasePacket implements IExtensionHeader { - public static final byte FIXED_HEADER_LENGTH = 12; // bytes - public static final byte LENGTH_UNIT = 4; // bytes per unit - public static final byte MINUS = 2; - - protected byte nextHeader; - protected byte payloadLength; - protected int securityParamIndex; - protected int sequence; - protected byte[] integrityCheck; - - @Override - public byte getNextHeader() { - return this.nextHeader; - } - - @Override - public Authentication setNextHeader(final byte nextHeader) { - this.nextHeader = nextHeader; - return this; - } - - /** - * Gets the payload length of this header. - * - * @return the payload length - */ - public byte getPayloadLength() { - return this.payloadLength; - } - - /** - * Sets the payload length of this header. - * - * @param payloadLength the payload length to set - * @return this - */ - public Authentication setPayloadLength(final byte payloadLength) { - this.payloadLength = payloadLength; - return this; - } - - /** - * Gets the security parameter index of this header. - * - * @return the security parameter index - */ - public int getSecurityParamIndex() { - return this.securityParamIndex; - } - - /** - * Sets the security parameter index of this header. - * - * @param securityParamIndex the security parameter index to set - * @return this - */ - public Authentication setSecurityParamIndex(final int securityParamIndex) { - this.securityParamIndex = securityParamIndex; - return this; - } - - /** - * Gets the sequence number of this header. - * - * @return the sequence number - */ - public int getSequence() { - return this.sequence; - } - - /** - * Sets the sequence number of this header. - * - * @param sequence the sequence number to set - * @return this - */ - public Authentication setSequence(final int sequence) { - this.sequence = sequence; - return this; - } - - /** - * Gets the integrity check value of this header. - * - * @return the integrity check value - */ - public byte[] getIntegrityCheck() { - return this.integrityCheck; - } - - /** - * Sets the integrity check value of this header. - * - * @param integrityCheck the integrity check value to set - * @return this - */ - public Authentication setIngegrityCheck(final byte[] integrityCheck) { - this.integrityCheck = - Arrays.copyOfRange(integrityCheck, 0, integrityCheck.length); - return this; - } - - /** - * Gets the total length of this header. - * According to spec, payload length should be the total length of this AH - * in 4-octet unit, minus 2 - * - * @return the total length - */ - public int getTotalLength() { - return (this.payloadLength + MINUS) * LENGTH_UNIT; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - int headerLength = FIXED_HEADER_LENGTH + integrityCheck.length; - int payloadLength = 0; - if (payloadData != null) { - payloadLength = payloadData.length; - } - - final byte[] data = new byte[headerLength + payloadLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.nextHeader); - bb.put(this.payloadLength); - bb.putShort((short) 0); - bb.putInt(this.securityParamIndex); - bb.putInt(this.sequence); - bb.put(this.integrityCheck, 0, integrityCheck.length); - - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof IExtensionHeader) { - ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_AH); - } - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.nextHeader = bb.get(); - this.payloadLength = bb.get(); - bb.getShort(); - this.securityParamIndex = bb.getInt(); - this.sequence = bb.getInt(); - int icvLength = getTotalLength() - FIXED_HEADER_LENGTH; - this.integrityCheck = new byte[icvLength]; - bb.get(this.integrityCheck, 0, icvLength); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader); - } else { - deserializer = Data.deserializer(); - } - - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.nextHeader; - result = prime * result + this.payloadLength; - result = prime * result + this.securityParamIndex; - result = prime * result + this.sequence; - for (byte b : this.integrityCheck) { - result = prime * result + b; - } - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof Authentication)) { - return false; - } - final Authentication other = (Authentication) obj; - if (this.nextHeader != other.nextHeader) { - return false; - } - if (this.payloadLength != other.payloadLength) { - return false; - } - if (this.securityParamIndex != other.securityParamIndex) { - return false; - } - if (this.sequence != other.sequence) { - return false; - } - if (!Arrays.equals(this.integrityCheck, other.integrityCheck)) { - return false; - } - return true; - } - - /** - * Deserializer function for authentication headers. - * - * @return deserializer function - */ - public static Deserializer<Authentication> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, FIXED_HEADER_LENGTH); - - Authentication authentication = new Authentication(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - authentication.nextHeader = bb.get(); - authentication.payloadLength = bb.get(); - bb.getShort(); - authentication.securityParamIndex = bb.getInt(); - authentication.sequence = bb.getInt(); - int icvLength = (authentication.payloadLength + MINUS) * LENGTH_UNIT - FIXED_HEADER_LENGTH; - authentication.integrityCheck = new byte[icvLength]; - bb.get(authentication.integrityCheck, 0, icvLength); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(authentication.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(authentication.nextHeader); - } else { - deserializer = Data.deserializer(); - } - authentication.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - authentication.payload.setParent(authentication); - - return authentication; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/BaseOptions.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/BaseOptions.java deleted file mode 100644 index f57b756e..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/BaseOptions.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Data; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.IPv6; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import static org.onlab.packet.PacketUtils.checkHeaderLength; -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Base class for hop-by-hop options and destination options. - */ -public class BaseOptions extends BasePacket implements IExtensionHeader { - public static final byte FIXED_HEADER_LENGTH = 2; // bytes - public static final byte FIXED_OPTIONS_LENGTH = 6; // bytes - public static final byte LENGTH_UNIT = 8; // bytes per unit - - protected byte nextHeader; - protected byte headerExtLength; - protected byte[] options; - protected byte type; - - @Override - public byte getNextHeader() { - return this.nextHeader; - } - - @Override - public BaseOptions setNextHeader(final byte nextHeader) { - this.nextHeader = nextHeader; - return this; - } - - /** - * Gets the extension length of this header. - * - * @return header length - */ - public byte getHeaderExtLength() { - return this.headerExtLength; - } - - /** - * Sets the extension length of this header. - * - * @param headerExtLength the header length to set - * @return this - */ - public BaseOptions setHeaderExtLength(final byte headerExtLength) { - this.headerExtLength = headerExtLength; - return this; - } - - /** - * Gets the options. - * - * @return the options - */ - public byte[] getOptions() { - return this.options; - } - - /** - * Sets the options. - * - * @param options the options to set - * @return this - */ - public BaseOptions setOptions(final byte[] options) { - this.options = - Arrays.copyOfRange(options, 0, options.length); - return this; - } - - /** - * Gets the type of this option. - * - * @return the type - */ - protected byte getType() { - return this.type; - } - - /** - * Sets the type of this option. - * Must be either IPv6.PROTOCOL_HOPOPT or IPv6.PROTOCOL_DSTOPT - * - * @param type the type to set - * @return this - */ - protected BaseOptions setType(final byte type) { - this.type = type; - return this; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - int headerLength = FIXED_HEADER_LENGTH + options.length; - int payloadLength = 0; - if (payloadData != null) { - payloadLength = payloadData.length; - } - - final byte[] data = new byte[headerLength + payloadLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.nextHeader); - bb.put(this.headerExtLength); - bb.put(this.options, 0, options.length); - - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof IExtensionHeader) { - ((IExtensionHeader) this.parent).setNextHeader(this.type); - } - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.nextHeader = bb.get(); - this.headerExtLength = bb.get(); - int optionLength = - FIXED_OPTIONS_LENGTH + LENGTH_UNIT * this.headerExtLength; - this.options = new byte[optionLength]; - bb.get(this.options, 0, optionLength); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader); - } else { - deserializer = Data.deserializer(); - } - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.nextHeader; - result = prime * result + this.headerExtLength; - for (byte b : this.options) { - result = prime * result + b; - } - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof BaseOptions)) { - return false; - } - final BaseOptions other = (BaseOptions) obj; - if (this.nextHeader != other.nextHeader) { - return false; - } - if (this.headerExtLength != other.headerExtLength) { - return false; - } - if (!Arrays.equals(this.options, other.options)) { - return false; - } - if (this.type != other.type) { - return false; - } - return true; - } - - /** - * Deserializer function for IPv6 base options. - * - * @return deserializer function - */ - public static Deserializer<BaseOptions> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, FIXED_HEADER_LENGTH); - - BaseOptions baseOptions = new BaseOptions(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - baseOptions.nextHeader = bb.get(); - baseOptions.headerExtLength = bb.get(); - int optionLength = - FIXED_OPTIONS_LENGTH + LENGTH_UNIT * baseOptions.headerExtLength; - - checkHeaderLength(bb.remaining(), optionLength); - - baseOptions.options = new byte[optionLength]; - bb.get(baseOptions.options, 0, optionLength); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(baseOptions.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(baseOptions.nextHeader); - } else { - deserializer = Data.deserializer(); - } - baseOptions.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - baseOptions.payload.setParent(baseOptions); - - return baseOptions; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/DestinationOptions.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/DestinationOptions.java deleted file mode 100644 index 208bdd7e..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/DestinationOptions.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.onlab.packet.IPv6; - -/** - * Implements IPv6 Destination Options extension header format. (RFC 2460) - */ -public class DestinationOptions extends BaseOptions { - public DestinationOptions() { - super(); - this.setType(IPv6.PROTOCOL_DSTOPT); - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/EncapSecurityPayload.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/EncapSecurityPayload.java deleted file mode 100644 index e46a1261..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/EncapSecurityPayload.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Data; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.IPv6; - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements IPv6 Encapsulating Security Payload (ESP) extension header format. - * (RFC 4303) - */ -public class EncapSecurityPayload extends BasePacket { - public static final byte HEADER_LENGTH = 8; // bytes - - protected int securityParamIndex; - protected int sequence; - // - // NOTE: The remaining fields including payload data, padding length and - // next header are encrypted and all considered as a payload of ESP. - // - - /** - * Gets the security parameter index of this header. - * - * @return the security parameter index - */ - public int getSecurityParamIndex() { - return this.securityParamIndex; - } - - /** - * Sets the security parameter index of this header. - * - * @param securityParamIndex the security parameter index to set - * @return this - */ - public EncapSecurityPayload setSecurityParamIndex(final int securityParamIndex) { - this.securityParamIndex = securityParamIndex; - return this; - } - - /** - * Gets the sequence number of this header. - * - * @return the sequence number - */ - public int getSequence() { - return this.sequence; - } - - /** - * Sets the sequence number of this header. - * - * @param sequence the sequence number to set - * @return this - */ - public EncapSecurityPayload setSequence(final int sequence) { - this.sequence = sequence; - return this; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - int payloadLength = 0; - if (payloadData != null) { - payloadLength = payloadData.length; - } - - final byte[] data = new byte[HEADER_LENGTH + payloadLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putInt(this.securityParamIndex); - bb.putInt(this.sequence); - - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof IExtensionHeader) { - ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_ESP); - } - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.securityParamIndex = bb.getInt(); - this.sequence = bb.getInt(); - - this.payload = new Data(); - this.payload.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.securityParamIndex; - result = prime * result + this.sequence; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof EncapSecurityPayload)) { - return false; - } - final EncapSecurityPayload other = (EncapSecurityPayload) obj; - if (this.securityParamIndex != other.securityParamIndex) { - return false; - } - if (this.sequence != other.sequence) { - return false; - } - return true; - } - - /** - * Deserializer function for encapsulated security payload headers. - * - * @return deserializer function - */ - public static Deserializer<EncapSecurityPayload> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - EncapSecurityPayload encapSecurityPayload = new EncapSecurityPayload(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - encapSecurityPayload.securityParamIndex = bb.getInt(); - encapSecurityPayload.sequence = bb.getInt(); - - encapSecurityPayload.payload = Data.deserializer().deserialize( - data, bb.position(), bb.limit() - bb.position()); - encapSecurityPayload.payload.setParent(encapSecurityPayload); - - return encapSecurityPayload; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Fragment.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Fragment.java deleted file mode 100644 index 68015d31..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Fragment.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Data; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.IPv6; - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements IPv6 fragment extension header format. (RFC 2460) - */ -public class Fragment extends BasePacket implements IExtensionHeader { - public static final byte HEADER_LENGTH = 8; // bytes - - protected byte nextHeader; - protected short fragmentOffset; - protected byte moreFragment; - protected int identification; - - @Override - public byte getNextHeader() { - return this.nextHeader; - } - - @Override - public Fragment setNextHeader(final byte nextHeader) { - this.nextHeader = nextHeader; - return this; - } - - /** - * Gets the fragment offset of this header. - * - * @return fragment offset - */ - public short getFragmentOffset() { - return this.fragmentOffset; - } - - /** - * Sets the fragment offset of this header. - * - * @param fragmentOffset the fragment offset to set - * @return this - */ - public Fragment setFragmentOffset(final short fragmentOffset) { - this.fragmentOffset = fragmentOffset; - return this; - } - - /** - * Gets the more fragment flag of this header. - * - * @return more fragment flag - */ - public byte getMoreFragment() { - return this.moreFragment; - } - - /** - * Sets the more fragment flag of this header. - * - * @param moreFragment the more fragment flag to set - * @return this - */ - public Fragment setMoreFragment(final byte moreFragment) { - this.moreFragment = moreFragment; - return this; - } - - /** - * Gets the identification of this header. - * - * @return identification - */ - public int getIdentification() { - return this.identification; - } - - /** - * Sets the identification of this header. - * - * @param identification the identification to set - * @return this - */ - public Fragment setIdentification(final int identification) { - this.identification = identification; - return this; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - int payloadLength = 0; - if (payloadData != null) { - payloadLength = payloadData.length; - } - - final byte[] data = new byte[HEADER_LENGTH + payloadLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.nextHeader); - bb.put((byte) 0); - bb.putShort((short) ( - (this.fragmentOffset & 0x1fff) << 3 | - this.moreFragment & 0x1 - )); - bb.putInt(this.identification); - - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof IExtensionHeader) { - ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_FRAG); - } - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.nextHeader = bb.get(); - bb.get(); - short sscratch = bb.getShort(); - this.fragmentOffset = (short) (sscratch >> 3 & 0x1fff); - this.moreFragment = (byte) (sscratch & 0x1); - this.identification = bb.getInt(); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader); - } else { - deserializer = Data.deserializer(); - } - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.nextHeader; - result = prime * result + this.fragmentOffset; - result = prime * result + this.moreFragment; - result = prime * result + this.identification; - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof Fragment)) { - return false; - } - final Fragment other = (Fragment) obj; - if (this.nextHeader != other.nextHeader) { - return false; - } - if (this.fragmentOffset != other.fragmentOffset) { - return false; - } - if (this.moreFragment != other.moreFragment) { - return false; - } - if (this.identification != other.identification) { - return false; - } - return true; - } - - /** - * Deserializer function for fragment headers. - * - * @return deserializer function - */ - public static Deserializer<Fragment> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - Fragment fragment = new Fragment(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - fragment.nextHeader = bb.get(); - bb.get(); - short sscratch = bb.getShort(); - fragment.fragmentOffset = (short) (sscratch >> 3 & 0x1fff); - fragment.moreFragment = (byte) (sscratch & 0x1); - fragment.identification = bb.getInt(); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(fragment.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(fragment.nextHeader); - } else { - deserializer = Data.deserializer(); - } - fragment.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - fragment.payload.setParent(fragment); - - return fragment; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/HopByHopOptions.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/HopByHopOptions.java deleted file mode 100644 index cd8c141c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/HopByHopOptions.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.onlab.packet.IPv6; - -/** - * Implements IPv6 Hop-by-hop Options extension header format. (RFC 2460) - */ -public class HopByHopOptions extends BaseOptions { - public HopByHopOptions() { - super(); - this.setType(IPv6.PROTOCOL_HOPOPT); - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/IExtensionHeader.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/IExtensionHeader.java deleted file mode 100644 index 252f1a3c..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/IExtensionHeader.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -/** - * Interface for IPv6 extension header. - */ -public interface IExtensionHeader { - /** - * Gets the type of next header. - * - * @return next header - */ - byte getNextHeader(); - - /** - * Sets the type of next header. - * - * @param nextHeader the next header to set - * @return this - */ - IExtensionHeader setNextHeader(final byte nextHeader); -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Routing.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Routing.java deleted file mode 100644 index d7d204a9..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/Routing.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Data; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.IPv6; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import static org.onlab.packet.PacketUtils.checkHeaderLength; -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements IPv6 routing extension header format. (RFC 2460) - */ -public class Routing extends BasePacket implements IExtensionHeader { - public static final byte FIXED_HEADER_LENGTH = 4; // bytes - public static final byte FIXED_ROUTING_DATA_LENGTH = 4; // bytes - public static final byte LENGTH_UNIT = 8; // bytes per unit - - protected byte nextHeader; - protected byte headerExtLength; - protected byte routingType; - protected byte segmentsLeft; - protected byte[] routingData; - - @Override - public byte getNextHeader() { - return this.nextHeader; - } - - @Override - public Routing setNextHeader(final byte nextHeader) { - this.nextHeader = nextHeader; - return this; - } - - /** - * Gets the extension length of this header. - * - * @return header length - */ - public byte getHeaderExtLength() { - return this.headerExtLength; - } - - /** - * Sets the extension length of this header. - * - * @param headerExtLength the header length to set - * @return this - */ - public Routing setHeaderExtLength(final byte headerExtLength) { - this.headerExtLength = headerExtLength; - return this; - } - - /** - * Gets the routing type of this header. - * - * @return routing type - */ - public byte getRoutingType() { - return this.routingType; - } - - /** - * Sets the routing type of this header. - * - * @param routingType the routing type to set - * @return this - */ - public Routing setRoutingType(final byte routingType) { - this.routingType = routingType; - return this; - } - - /** - * Gets the number of remaining route segments of this header. - * - * @return number of remaining route segments - */ - public byte getSegmentsLeft() { - return this.segmentsLeft; - } - - /** - * Sets the number of remaining route segments of this header. - * - * @param segmentsLeft the number of remaining route segments to set - * @return this - */ - public Routing setSegmntsLeft(final byte segmentsLeft) { - this.segmentsLeft = segmentsLeft; - return this; - } - - /** - * Gets the routing data. - * - * @return the routing data - */ - public byte[] getRoutingData() { - return this.routingData; - } - - /** - * Sets the routing data. - * - * @param routingData the routing data to set - * @return this - */ - public Routing setRoutingData(final byte[] routingData) { - this.routingData = - Arrays.copyOfRange(routingData, 0, routingData.length); - return this; - } - - @Override - public byte[] serialize() { - byte[] payloadData = null; - if (this.payload != null) { - this.payload.setParent(this); - payloadData = this.payload.serialize(); - } - - int headerLength = FIXED_HEADER_LENGTH + routingData.length; - int payloadLength = 0; - if (payloadData != null) { - payloadLength = payloadData.length; - } - - final byte[] data = new byte[headerLength + payloadLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.nextHeader); - bb.put(this.headerExtLength); - bb.put(this.routingType); - bb.put(this.segmentsLeft); - bb.put(this.routingData, 0, routingData.length); - - if (payloadData != null) { - bb.put(payloadData); - } - - if (this.parent != null && this.parent instanceof IExtensionHeader) { - ((IExtensionHeader) this.parent).setNextHeader(IPv6.PROTOCOL_ROUTING); - } - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - this.nextHeader = bb.get(); - this.headerExtLength = bb.get(); - this.routingType = bb.get(); - this.segmentsLeft = bb.get(); - int dataLength = - FIXED_ROUTING_DATA_LENGTH + LENGTH_UNIT * this.headerExtLength; - this.routingData = new byte[dataLength]; - bb.get(this.routingData, 0, dataLength); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(this.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(this.nextHeader); - } else { - deserializer = new Data().deserializer(); - } - try { - this.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - this.payload.setParent(this); - } catch (DeserializationException e) { - return this; - } - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.nextHeader; - result = prime * result + this.headerExtLength; - result = prime * result + this.routingType; - result = prime * result + this.segmentsLeft; - for (byte b : this.routingData) { - result = prime * result + b; - } - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof Routing)) { - return false; - } - final Routing other = (Routing) obj; - if (this.nextHeader != other.nextHeader) { - return false; - } - if (this.headerExtLength != other.headerExtLength) { - return false; - } - if (this.routingType != other.routingType) { - return false; - } - if (this.segmentsLeft != other.segmentsLeft) { - return false; - } - if (!Arrays.equals(this.routingData, other.routingData)) { - return false; - } - return true; - } - - /** - * Deserializer function for routing headers. - * - * @return deserializer function - */ - public static Deserializer<Routing> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, FIXED_HEADER_LENGTH); - - Routing routing = new Routing(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - routing.nextHeader = bb.get(); - routing.headerExtLength = bb.get(); - routing.routingType = bb.get(); - routing.segmentsLeft = bb.get(); - int dataLength = - FIXED_ROUTING_DATA_LENGTH + LENGTH_UNIT * routing.headerExtLength; - - checkHeaderLength(bb.remaining(), dataLength); - - routing.routingData = new byte[dataLength]; - bb.get(routing.routingData, 0, dataLength); - - Deserializer<? extends IPacket> deserializer; - if (IPv6.PROTOCOL_DESERIALIZER_MAP.containsKey(routing.nextHeader)) { - deserializer = IPv6.PROTOCOL_DESERIALIZER_MAP.get(routing.nextHeader); - } else { - deserializer = new Data().deserializer(); - } - routing.payload = deserializer.deserialize(data, bb.position(), - bb.limit() - bb.position()); - routing.payload.setParent(routing); - - return routing; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/package-info.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/package-info.java deleted file mode 100644 index 714fd1b2..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ipv6/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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. - */ - -/** - * Utilities for decoding and encoding IPv6 extension headers. - */ -package org.onlab.packet.ipv6; diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborAdvertisement.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborAdvertisement.java deleted file mode 100644 index 99fa0dd6..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborAdvertisement.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.Ip6Address; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.List; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements ICMPv6 Neighbor Advertisement packet format (RFC 4861). - */ -public class NeighborAdvertisement extends BasePacket { - public static final byte HEADER_LENGTH = 20; // bytes - - protected byte routerFlag; - protected byte solicitedFlag; - protected byte overrideFlag; - protected byte[] targetAddress = new byte[Ip6Address.BYTE_LENGTH]; - - private final NeighborDiscoveryOptions options = - new NeighborDiscoveryOptions(); - - /** - * Gets router flag. - * - * @return the router flag - */ - public byte getRouterFlag() { - return this.routerFlag; - } - - /** - * Sets router flag. - * - * @param routerFlag the router flag to set - * @return this - */ - public NeighborAdvertisement setRouterFlag(final byte routerFlag) { - this.routerFlag = routerFlag; - return this; - } - - /** - * Gets solicited flag. - * - * @return the solicited flag - */ - public byte getSolicitedFlag() { - return this.solicitedFlag; - } - - /** - * Sets solicited flag. - * - * @param solicitedFlag the solicited flag to set - * @return this - */ - public NeighborAdvertisement setSolicitedFlag(final byte solicitedFlag) { - this.solicitedFlag = solicitedFlag; - return this; - } - - /** - * Gets override flag. - * - * @return the override flag - */ - public byte getOverrideFlag() { - return this.overrideFlag; - } - - /** - * Sets override flag. - * - * @param overrideFlag the override flag to set - * @return this - */ - public NeighborAdvertisement setOverrideFlag(final byte overrideFlag) { - this.overrideFlag = overrideFlag; - return this; - } - - /** - * Gets target address. - * - * @return the target IPv6 address - */ - public byte[] getTargetAddress() { - return this.targetAddress; - } - - /** - * Sets target address. - * - * @param targetAddress the target IPv6 address to set - * @return this - */ - public NeighborAdvertisement setTargetAddress(final byte[] targetAddress) { - this.targetAddress = - Arrays.copyOfRange(targetAddress, 0, Ip6Address.BYTE_LENGTH); - return this; - } - - /** - * Gets the Neighbor Discovery Protocol packet options. - * - * @return the Neighbor Discovery Protocol packet options - */ - public List<NeighborDiscoveryOptions.Option> getOptions() { - return this.options.options(); - } - - /** - * Adds a Neighbor Discovery Protocol packet option. - * - * @param type the option type - * @param data the option data - * @return this - */ - public NeighborAdvertisement addOption(final byte type, - final byte[] data) { - this.options.addOption(type, data); - return this; - } - - @Override - public byte[] serialize() { - byte[] optionsData = null; - if (this.options.hasOptions()) { - optionsData = this.options.serialize(); - } - - int optionsLength = 0; - if (optionsData != null) { - optionsLength = optionsData.length; - } - - final byte[] data = new byte[HEADER_LENGTH + optionsLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putInt((this.routerFlag & 0x1) << 31 | - (this.solicitedFlag & 0x1) << 30 | - (this.overrideFlag & 0x1) << 29); - bb.put(this.targetAddress, 0, Ip6Address.BYTE_LENGTH); - if (optionsData != null) { - bb.put(optionsData); - } - - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - int iscratch; - - iscratch = bb.getInt(); - this.routerFlag = (byte) (iscratch >> 31 & 0x1); - this.solicitedFlag = (byte) (iscratch >> 30 & 0x1); - this.overrideFlag = (byte) (iscratch >> 29 & 0x1); - bb.get(this.targetAddress, 0, Ip6Address.BYTE_LENGTH); - - this.options.deserialize(data, bb.position(), - bb.limit() - bb.position()); - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - ByteBuffer bb; - result = prime * result + this.routerFlag; - result = prime * result + this.solicitedFlag; - result = prime * result + this.overrideFlag; - bb = ByteBuffer.wrap(this.targetAddress); - for (int i = 0; i < this.targetAddress.length / 4; i++) { - result = prime * result + bb.getInt(); - } - result = prime * result + this.options.hashCode(); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof NeighborAdvertisement)) { - return false; - } - final NeighborAdvertisement other = (NeighborAdvertisement) obj; - if (this.routerFlag != other.routerFlag) { - return false; - } - if (this.solicitedFlag != other.solicitedFlag) { - return false; - } - if (this.overrideFlag != other.overrideFlag) { - return false; - } - if (!Arrays.equals(this.targetAddress, other.targetAddress)) { - return false; - } - if (!this.options.equals(other.options)) { - return false; - } - return true; - } - - /** - * Deserializer function for neighbor advertisement packets. - * - * @return deserializer function - */ - public static Deserializer<NeighborAdvertisement> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - NeighborAdvertisement neighborAdvertisement = new NeighborAdvertisement(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - int iscratch; - - iscratch = bb.getInt(); - neighborAdvertisement.routerFlag = (byte) (iscratch >> 31 & 0x1); - neighborAdvertisement.solicitedFlag = (byte) (iscratch >> 30 & 0x1); - neighborAdvertisement.overrideFlag = (byte) (iscratch >> 29 & 0x1); - bb.get(neighborAdvertisement.targetAddress, 0, Ip6Address.BYTE_LENGTH); - - if (bb.limit() - bb.position() > 0) { - NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer() - .deserialize(data, bb.position(), bb.limit() - bb.position()); - - for (NeighborDiscoveryOptions.Option option : options.options()) { - neighborAdvertisement.addOption(option.type(), option.data()); - } - } - - return neighborAdvertisement; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborDiscoveryOptions.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborDiscoveryOptions.java deleted file mode 100644 index 00a26068..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborDiscoveryOptions.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Neighbor Discovery Protocol packet options. - */ -public class NeighborDiscoveryOptions extends BasePacket { - public static final byte TYPE_SOURCE_LL_ADDRESS = 1; - public static final byte TYPE_TARGET_LL_ADDRESS = 2; - public static final byte TYPE_PREFIX_INFORMATION = 3; - public static final byte TYPE_REDIRECTED_HEADER = 4; - public static final byte TYPE_MTU = 5; - - public static final byte INITIAL_HEADER_REQUIRED = 2; - - private static final String BUFFER_UNDERFLOW_ERROR = - "Not enough bytes in buffer to read option"; - - private final List<Option> options = new ArrayList<>(); - - /** - * Packet option. - */ - public final class Option { - private final byte type; - private final byte[] data; - - /** - * Constructor. - * - * @param type the option type - * @param data the option data - */ - private Option(byte type, byte[] data) { - this.type = type; - this.data = Arrays.copyOfRange(data, 0, data.length); - } - - /** - * Gets the option type. - * - * @return the option type - */ - public byte type() { - return this.type; - } - - /** - * Gets the option data. - * - * @return the option data - */ - public byte[] data() { - return this.data; - } - - /** - * Gets the option data length (in number of octets). - * - * @return the option data length (in number of octets) - */ - public int dataLength() { - return data.length; - } - - /** - * Gets the option length (in number of octets), including the type and - * length fields (one octet each). - * - * @return the option length (in number of octets), including the type - * and length fields - */ - private int optionLength() { - return 2 + dataLength(); - } - - /** - * Gets the option length field value (in units of 8 octets). - * - * @return the option length field value (in units of 8 octets) - */ - private byte optionLengthField() { - return (byte) ((optionLength() + 7) / 8); - } - - /** - * Gets the option length on the wire (in number of octets). - * - * @return the option length on the wire (in number of octets) - */ - private int optionWireLength() { - return 8 * optionLengthField(); - } - } - - /** - * Adds a Neighbor Discovery Protocol packet option. - * - * @param type the option type - * @param data the option data - * @return this - */ - public NeighborDiscoveryOptions addOption(byte type, byte[] data) { - options.add(new Option(type, data)); - return this; - } - - /** - * Gets the Neighbor Discovery Protocol packet options. - * - * @return the Neighbor Discovery Protocol packet options - */ - public List<NeighborDiscoveryOptions.Option> options() { - return this.options; - } - - /** - * Checks whether any options are included. - * - * @return true if options are included, otherwise false - */ - public boolean hasOptions() { - return !this.options.isEmpty(); - } - - @Override - public byte[] serialize() { - // Compute first the total length on the wire for all options - - int wireLength = 0; - - for (Option option : this.options) { - wireLength += option.optionWireLength(); - } - - final byte[] data = new byte[wireLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - // - // Serialize all options - // - for (Option option : this.options) { - bb.put(option.type()); - bb.put(option.optionLengthField()); - bb.put(option.data()); - // Add the padding - int paddingLength = - option.optionWireLength() - option.optionLength(); - for (int i = 0; i < paddingLength; i++) { - bb.put((byte) 0); - } - } - - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - options.clear(); - - // - // Deserialize all options - // - while (bb.hasRemaining()) { - byte type = bb.get(); - if (!bb.hasRemaining()) { - break; - } - byte lengthField = bb.get(); - int dataLength = lengthField * 8; // The data length field is in - // unit of 8 octets - - // Exclude the type and length fields - if (dataLength < 2) { - break; - } - dataLength -= 2; - - if (bb.remaining() < dataLength) { - break; - } - byte[] optionData = new byte[dataLength]; - bb.get(optionData, 0, optionData.length); - addOption(type, optionData); - } - - return this; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - - for (Option option : this.options) { - result = prime * result + option.type(); - result = prime * result + Arrays.hashCode(option.data()); - } - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof NeighborDiscoveryOptions) { - NeighborDiscoveryOptions other = (NeighborDiscoveryOptions) obj; - return this.options.equals(other.options); - } - return false; - } - - public static Deserializer<NeighborDiscoveryOptions> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, INITIAL_HEADER_REQUIRED); - - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - NeighborDiscoveryOptions ndo = new NeighborDiscoveryOptions(); - - ndo.options.clear(); - - // - // Deserialize all options - // - while (bb.hasRemaining()) { - byte type = bb.get(); - if (!bb.hasRemaining()) { - throw new DeserializationException(BUFFER_UNDERFLOW_ERROR); - } - byte lengthField = bb.get(); - int dataLength = lengthField * 8; // The data length field is in - // unit of 8 octets - - // Exclude the type and length fields - if (dataLength < 2) { - break; - } - dataLength -= 2; - - if (bb.remaining() < dataLength) { - throw new DeserializationException(BUFFER_UNDERFLOW_ERROR); - } - byte[] optionData = new byte[dataLength]; - bb.get(optionData, 0, optionData.length); - ndo.addOption(type, optionData); - } - - return ndo; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java deleted file mode 100644 index 77c119a0..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.Ip6Address; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.List; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements ICMPv6 Neighbor Solicitation packet format. (RFC 4861) - */ -public class NeighborSolicitation extends BasePacket { - public static final byte HEADER_LENGTH = 20; // bytes - - protected byte[] targetAddress = new byte[Ip6Address.BYTE_LENGTH]; - - private final NeighborDiscoveryOptions options = - new NeighborDiscoveryOptions(); - - /** - * Gets target address. - * - * @return the target IPv6 address - */ - public byte[] getTargetAddress() { - return this.targetAddress; - } - - /** - * Sets target address. - * - * @param targetAddress the target IPv6 address to set - * @return this - */ - public NeighborSolicitation setTargetAddress(final byte[] targetAddress) { - this.targetAddress = - Arrays.copyOfRange(targetAddress, 0, Ip6Address.BYTE_LENGTH); - return this; - } - - /** - * Gets the Neighbor Discovery Protocol packet options. - * - * @return the Neighbor Discovery Protocol packet options - */ - public List<NeighborDiscoveryOptions.Option> getOptions() { - return this.options.options(); - } - - /** - * Adds a Neighbor Discovery Protocol packet option. - * - * @param type the option type - * @param data the option data - * @return this - */ - public NeighborSolicitation addOption(final byte type, - final byte[] data) { - this.options.addOption(type, data); - return this; - } - - @Override - public byte[] serialize() { - byte[] optionsData = null; - if (this.options.hasOptions()) { - optionsData = this.options.serialize(); - } - - int optionsLength = 0; - if (optionsData != null) { - optionsLength = optionsData.length; - } - - final byte[] data = new byte[HEADER_LENGTH + optionsLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putInt(0); - bb.put(this.targetAddress, 0, Ip6Address.BYTE_LENGTH); - if (optionsData != null) { - bb.put(optionsData); - } - - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - bb.getInt(); - bb.get(this.targetAddress, 0, Ip6Address.BYTE_LENGTH); - - this.options.deserialize(data, bb.position(), - bb.limit() - bb.position()); - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - ByteBuffer bb; - bb = ByteBuffer.wrap(this.targetAddress); - for (int i = 0; i < this.targetAddress.length / 4; i++) { - result = prime * result + bb.getInt(); - } - result = prime * result + this.options.hashCode(); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof NeighborSolicitation)) { - return false; - } - final NeighborSolicitation other = (NeighborSolicitation) obj; - if (!Arrays.equals(this.targetAddress, other.targetAddress)) { - return false; - } - if (!this.options.equals(other.options)) { - return false; - } - return true; - } - - /** - * Deserializer function for neighbor solicitation packets. - * - * @return deserializer function - */ - public static Deserializer<NeighborSolicitation> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - NeighborSolicitation neighborSolicitation = new NeighborSolicitation(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - bb.getInt(); - bb.get(neighborSolicitation.targetAddress, 0, Ip6Address.BYTE_LENGTH); - - if (bb.limit() - bb.position() > 0) { - NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer() - .deserialize(data, bb.position(), bb.limit() - bb.position()); - - for (NeighborDiscoveryOptions.Option option : options.options()) { - neighborSolicitation.addOption(option.type(), option.data()); - } - } - - return neighborSolicitation; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/Redirect.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/Redirect.java deleted file mode 100644 index 51256d41..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/Redirect.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.Ip6Address; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.List; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements ICMPv6 Redirect packet format. (RFC 4861) - */ -public class Redirect extends BasePacket { - public static final byte HEADER_LENGTH = 36; // bytes - - protected byte[] targetAddress = new byte[Ip6Address.BYTE_LENGTH]; - protected byte[] destinationAddress = new byte[Ip6Address.BYTE_LENGTH]; - - private final NeighborDiscoveryOptions options = - new NeighborDiscoveryOptions(); - - /** - * Gets target address. - * - * @return the target IPv6 address - */ - public byte[] getTargetAddress() { - return this.targetAddress; - } - - /** - * Sets target address. - * - * @param targetAddress the target IPv6 address to set - * @return this - */ - public Redirect setTargetAddress(final byte[] targetAddress) { - this.targetAddress = - Arrays.copyOfRange(targetAddress, 0, Ip6Address.BYTE_LENGTH); - return this; - } - - /** - * Gets destination address. - * - * @return the destination IPv6 address - */ - public byte[] getDestinationAddress() { - return this.destinationAddress; - } - - /** - * Sets destination address. - * - * @param destinationAddress the destination IPv6 address to set - * @return this - */ - public Redirect setDestinationAddress(final byte[] destinationAddress) { - this.destinationAddress = - Arrays.copyOfRange(destinationAddress, 0, Ip6Address.BYTE_LENGTH); - return this; - } - - /** - * Gets the Neighbor Discovery Protocol packet options. - * - * @return the Neighbor Discovery Protocol packet options - */ - public List<NeighborDiscoveryOptions.Option> getOptions() { - return this.options.options(); - } - - /** - * Adds a Neighbor Discovery Protocol packet option. - * - * @param type the option type - * @param data the option data - * @return this - */ - public Redirect addOption(final byte type, final byte[] data) { - this.options.addOption(type, data); - return this; - } - - @Override - public byte[] serialize() { - byte[] optionsData = null; - if (this.options.hasOptions()) { - optionsData = this.options.serialize(); - } - - int optionsLength = 0; - if (optionsData != null) { - optionsLength = optionsData.length; - } - - final byte[] data = new byte[HEADER_LENGTH + optionsLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putInt(0); - bb.put(this.targetAddress, 0, Ip6Address.BYTE_LENGTH); - bb.put(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH); - if (optionsData != null) { - bb.put(optionsData); - } - - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - bb.getInt(); - bb.get(this.targetAddress, 0, Ip6Address.BYTE_LENGTH); - bb.get(this.destinationAddress, 0, Ip6Address.BYTE_LENGTH); - - this.options.deserialize(data, bb.position(), - bb.limit() - bb.position()); - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - ByteBuffer bb; - bb = ByteBuffer.wrap(this.targetAddress); - for (int i = 0; i < this.targetAddress.length / 4; i++) { - result = prime * result + bb.getInt(); - } - bb = ByteBuffer.wrap(this.destinationAddress); - for (int i = 0; i < this.destinationAddress.length / 4; i++) { - result = prime * result + bb.getInt(); - } - result = prime * result + this.options.hashCode(); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof Redirect)) { - return false; - } - final Redirect other = (Redirect) obj; - if (!Arrays.equals(this.targetAddress, other.targetAddress)) { - return false; - } - if (!Arrays.equals(this.destinationAddress, - other.destinationAddress)) { - return false; - } - if (!this.options.equals(other.options)) { - return false; - } - return true; - } - - /** - * Deserializer function for redirect packets. - * - * @return deserializer function - */ - public static Deserializer<Redirect> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - Redirect redirect = new Redirect(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - bb.getInt(); - - bb.get(redirect.targetAddress, 0, Ip6Address.BYTE_LENGTH); - bb.get(redirect.destinationAddress, 0, Ip6Address.BYTE_LENGTH); - - if (bb.limit() - bb.position() > 0) { - NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer() - .deserialize(data, bb.position(), bb.limit() - bb.position()); - - for (NeighborDiscoveryOptions.Option option : options.options()) { - redirect.addOption(option.type(), option.data()); - } - } - - return redirect; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/RouterAdvertisement.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/RouterAdvertisement.java deleted file mode 100644 index 597fc9f8..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/RouterAdvertisement.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; - -import java.nio.ByteBuffer; -import java.util.List; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements ICMPv6 Router Advertisement packet format. (RFC 4861) - */ -public class RouterAdvertisement extends BasePacket { - public static final byte HEADER_LENGTH = 12; // bytes - - protected byte currentHopLimit; - protected byte mFlag; - protected byte oFlag; - protected short routerLifetime; - protected int reachableTime; - protected int retransmitTimer; - - private final NeighborDiscoveryOptions options = - new NeighborDiscoveryOptions(); - - /** - * Gets current hop limit. - * - * @return the current hop limit - */ - public byte getCurrentHopLimit() { - return this.currentHopLimit; - } - - /** - * Sets current hop limit. - * - * @param currentHopLimit the current hop limit to set - * @return this - */ - public RouterAdvertisement setCurrentHopLimit(final byte currentHopLimit) { - this.currentHopLimit = currentHopLimit; - return this; - } - - /** - * Gets managed address configuration flag. - * - * @return the managed address configuration flag - */ - public byte getMFlag() { - return this.mFlag; - } - - /** - * Sets managed address configuration flag. - * - * @param mFlag the managed address configuration flag to set - * @return this - */ - public RouterAdvertisement setMFlag(final byte mFlag) { - this.mFlag = mFlag; - return this; - } - - /** - * Gets other configuration flag. - * - * @return the other configuration flag - */ - public byte getOFlag() { - return this.oFlag; - } - - /** - * Sets other configuration flag. - * - * @param oFlag the other configuration flag to set - * @return this - */ - public RouterAdvertisement setOFlag(final byte oFlag) { - this.oFlag = oFlag; - return this; - } - - /** - * Gets router lifetime. - * - * @return the router lifetime - */ - public short getRouterLifetime() { - return this.routerLifetime; - } - - /** - * Sets router lifetime. - * - * @param routerLifetime the router lifetime to set - * @return this - */ - public RouterAdvertisement setRouterLifetime(final short routerLifetime) { - this.routerLifetime = routerLifetime; - return this; - } - - /** - * Gets reachable time. - * - * @return the reachable time - */ - public int getReachableTime() { - return this.reachableTime; - } - - /** - * Sets reachable time. - * - * @param reachableTime the reachable time to set - * @return this - */ - public RouterAdvertisement setReachableTime(final int reachableTime) { - this.reachableTime = reachableTime; - return this; - } - - /** - * Gets retransmission timer. - * - * @return the retransmission timer - */ - public int getRetransmitTimer() { - return this.retransmitTimer; - } - - /** - * Sets retransmission timer. - * - * @param retransmitTimer the retransmission timer to set - * @return this - */ - public RouterAdvertisement setRetransmitTimer(final int retransmitTimer) { - this.retransmitTimer = retransmitTimer; - return this; - } - - /** - * Gets the Neighbor Discovery Protocol packet options. - * - * @return the Neighbor Discovery Protocol packet options - */ - public List<NeighborDiscoveryOptions.Option> getOptions() { - return this.options.options(); - } - - /** - * Adds a Neighbor Discovery Protocol packet option. - * - * @param type the option type - * @param data the option data - * @return this - */ - public RouterAdvertisement addOption(final byte type, final byte[] data) { - this.options.addOption(type, data); - return this; - } - - @Override - public byte[] serialize() { - byte[] optionsData = null; - if (this.options.hasOptions()) { - optionsData = this.options.serialize(); - } - - int optionsLength = 0; - if (optionsData != null) { - optionsLength = optionsData.length; - } - - final byte[] data = new byte[HEADER_LENGTH + optionsLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.currentHopLimit); - bb.put((byte) ((this.mFlag & 0x1) << 7 | (this.oFlag & 0x1) << 6)); - bb.putShort(routerLifetime); - bb.putInt(reachableTime); - bb.putInt(retransmitTimer); - - if (optionsData != null) { - bb.put(optionsData); - } - - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - int bscratch; - - this.currentHopLimit = bb.get(); - bscratch = bb.get(); - this.mFlag = (byte) ((bscratch >> 7) & 0x1); - this.oFlag = (byte) ((bscratch >> 6) & 0x1); - this.routerLifetime = bb.getShort(); - this.reachableTime = bb.getInt(); - this.retransmitTimer = bb.getInt(); - - this.options.deserialize(data, bb.position(), - bb.limit() - bb.position()); - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.currentHopLimit; - result = prime * result + this.mFlag; - result = prime * result + this.oFlag; - result = prime * result + this.routerLifetime; - result = prime * result + this.reachableTime; - result = prime * result + this.retransmitTimer; - result = prime * result + this.options.hashCode(); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof RouterAdvertisement)) { - return false; - } - final RouterAdvertisement other = (RouterAdvertisement) obj; - if (this.currentHopLimit != other.currentHopLimit) { - return false; - } - if (this.mFlag != other.mFlag) { - return false; - } - if (this.oFlag != other.oFlag) { - return false; - } - if (this.routerLifetime != other.routerLifetime) { - return false; - } - if (this.reachableTime != other.reachableTime) { - return false; - } - if (this.retransmitTimer != other.retransmitTimer) { - return false; - } - if (!this.options.equals(other.options)) { - return false; - } - return true; - } - - /** - * Deserializer function for router advertisement packets. - * - * @return deserializer function - */ - public static Deserializer<RouterAdvertisement> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - RouterAdvertisement routerAdvertisement = new RouterAdvertisement(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - int bscratch; - - routerAdvertisement.currentHopLimit = bb.get(); - bscratch = bb.get(); - routerAdvertisement.mFlag = (byte) ((bscratch >> 7) & 0x1); - routerAdvertisement.oFlag = (byte) ((bscratch >> 6) & 0x1); - routerAdvertisement.routerLifetime = bb.getShort(); - routerAdvertisement.reachableTime = bb.getInt(); - routerAdvertisement.retransmitTimer = bb.getInt(); - - if (bb.limit() - bb.position() > 0) { - NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer() - .deserialize(data, bb.position(), bb.limit() - bb.position()); - - for (NeighborDiscoveryOptions.Option option : options.options()) { - routerAdvertisement.addOption(option.type(), option.data()); - } - } - - return routerAdvertisement; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/RouterSolicitation.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/RouterSolicitation.java deleted file mode 100644 index e279a404..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/RouterSolicitation.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; - -import java.nio.ByteBuffer; -import java.util.List; - -import static org.onlab.packet.PacketUtils.checkInput; - -/** - * Implements ICMPv6 Router Solicitation packet format. (RFC 4861) - */ -public class RouterSolicitation extends BasePacket { - public static final byte HEADER_LENGTH = 4; // bytes - - private final NeighborDiscoveryOptions options = new NeighborDiscoveryOptions(); - - /** - * Gets the Neighbor Discovery Protocol packet options. - * - * @return the Neighbor Discovery Protocol packet options - */ - public List<NeighborDiscoveryOptions.Option> getOptions() { - return this.options.options(); - } - - /** - * Adds a Neighbor Discovery Protocol packet option. - * - * @param type the option type - * @param data the option data - * @return this - */ - public RouterSolicitation addOption(final byte type, final byte[] data) { - this.options.addOption(type, data); - return this; - } - - @Override - public byte[] serialize() { - byte[] optionsData = null; - if (this.options.hasOptions()) { - optionsData = this.options.serialize(); - } - - int optionsLength = 0; - if (optionsData != null) { - optionsLength = optionsData.length; - } - - final byte[] data = new byte[HEADER_LENGTH + optionsLength]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.putInt(0); - - if (optionsData != null) { - bb.put(optionsData); - } - - return data; - } - - @Override - public IPacket deserialize(byte[] data, int offset, int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - bb.getInt(); - - this.options.deserialize(data, bb.position(), - bb.limit() - bb.position()); - - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 5807; - int result = super.hashCode(); - result = prime * result + this.options.hashCode(); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof RouterSolicitation)) { - return false; - } - final RouterSolicitation other = (RouterSolicitation) obj; - if (!this.options.equals(other.options)) { - return false; - } - return true; - } - - /** - * Deserializer function for router solicitation packets. - * - * @return deserializer function - */ - public static Deserializer<RouterSolicitation> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, HEADER_LENGTH); - - RouterSolicitation routerSolicitation = new RouterSolicitation(); - - ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - bb.getInt(); - - if (bb.limit() - bb.position() > 0) { - NeighborDiscoveryOptions options = NeighborDiscoveryOptions.deserializer() - .deserialize(data, bb.position(), bb.limit() - bb.position()); - - for (NeighborDiscoveryOptions.Option option : options.options()) { - routerSolicitation.addOption(option.type(), option.data()); - } - } - - return routerSolicitation; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/package-info.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/package-info.java deleted file mode 100644 index c62b1fba..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ndp/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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. - */ - -/** - * Utilities for decoding and encoding packets of Neighbor Discovery Protocol - * for IPv6 (RFC 4861). - */ -package org.onlab.packet.ndp; diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/package-info.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/package-info.java deleted file mode 100644 index e8e0cb5e..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Utilities for decoding and encoding packets of various network protocols - * and encapsulations. - */ -package org.onlab.packet; diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java deleted file mode 100644 index 0db82afb..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrGroup.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet.pim; - -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Ip4Address; -import org.onlab.packet.Ip6Address; -import org.onlab.packet.IpAddress; -import org.onlab.packet.IpPrefix; -import org.onlab.packet.PIM; - - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.checkInput; - -public class PIMAddrGroup { - private byte family; - private byte encType; - private byte reserved; - private boolean bBit; - private boolean zBit; - private byte masklen; - IpAddress addr; - - public static final int ENC_GROUP_IPV4_BYTE_LENGTH = 4 + Ip4Address.BYTE_LENGTH; - public static final int ENC_GROUP_IPV6_BYTE_LENGTH = 4 + Ip6Address.BYTE_LENGTH; - - /** - * PIM Encoded Group Address. - */ - public PIMAddrGroup() { - this.family = PIM.ADDRESS_FAMILY_IP4; - this.encType = 0; - this.reserved = 0; - this.bBit = false; - this.zBit = false; - } - - /** - * PIM Encoded Source Address. - * - * @param addr IPv4 or IPv6 - */ - public PIMAddrGroup(String addr) { - this.setAddr(addr); - } - - /** - * PIM Encoded Group Address. - * - * @param gpfx PIM encoded group address. - */ - public PIMAddrGroup(IpPrefix gpfx) { - this.setAddr(gpfx); - } - - /** - * PIM encoded source address. - * - * @param addr IPv4 or IPv6 - */ - public void setAddr(String addr) { - setAddr(IpPrefix.valueOf(addr)); - } - - /** - * Set the encoded source address. - * - * @param pfx address prefix - */ - public void setAddr(IpPrefix pfx) { - this.addr = pfx.address(); - this.masklen = (byte) pfx.prefixLength(); - this.family = (byte) ((this.addr.isIp4()) ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6); - } - - /** - * Get the IP family of this address: 4 or 6. - * - * @return the IP address family - */ - public int getFamily() { - return this.family; - } - - /** - * Get the address of this encoded address. - * - * @return source address - */ - public IpAddress getAddr() { - return this.addr; - } - - /** - * Get the masklen of the group address. - * - * @return the masklen - */ - public int getMasklen() { - return this.masklen; - } - - /** - * Return the z bit for admin scoping. Only used for the Bootstrap router. - * - * @return true or false - */ - public boolean getZBit() { - return this.zBit; - } - - /** - * Return the bBit. Used to indicate this is a bidir - * - * @return return true or false. - */ - public boolean getBBit() { - return this.bBit; - } - - /** - * The size in bytes of a serialized address. - * - * @return the number of bytes when serialized - */ - public int getByteSize() { - int size = 4; - size += addr.isIp4() ? 4 : 16; - return size; - } - - /** - * Serialize this group address. - * - * @return the serialized address in a buffer - */ - public byte[] serialize() { - int len = getByteSize(); - - final byte[] data = new byte[len]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.family); - bb.put(this.encType); - - // Todo: technically we should be setting the B and Z bits, but we'll never use them. - bb.put(reserved); - - bb.put(this.masklen); - bb.put(this.addr.toOctets()); - return data; - } - - /** - * Deserialze from a ByteBuffer. - * - * @param bb the ByteBuffer - * @return an encoded PIM group address - * @throws DeserializationException if unable to deserialize the packet data - */ - public PIMAddrGroup deserialize(ByteBuffer bb) throws DeserializationException { - - /* - * We need to verify that we have enough buffer space. First we'll assume that - * we are decoding an IPv4 address. After we read the first by (address family), - * we'll determine if we actually need more buffer space for an IPv6 address. - */ - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV4_BYTE_LENGTH); - - this.family = bb.get(); - if (family != PIM.ADDRESS_FAMILY_IP4 && family != PIM.ADDRESS_FAMILY_IP6) { - throw new DeserializationException("Illegal IP version number: " + family + "\n"); - } else if (family == PIM.ADDRESS_FAMILY_IP6) { - - // Check for one less by since we have already read the first byte of the packet. - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_GROUP_IPV6_BYTE_LENGTH - 1); - } - - this.encType = bb.get(); - this.reserved = bb.get(); - if ((this.reserved & 0x80) != 0) { - this.bBit = true; - } - if ((this.reserved & 0x01) != 0) { - this.zBit = true; - } - // Remove the z and b bits from reserved - this.reserved |= 0x7d; - - this.masklen = bb.get(); - if (this.family == PIM.ADDRESS_FAMILY_IP4) { - this.addr = IpAddress.valueOf(bb.getInt()); - } else if (this.family == PIM.ADDRESS_FAMILY_IP6) { - this.addr = Ip6Address.valueOf(bb.array(), 2); - } - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - result = prime * result + this.family; - result = prime * result + this.encType; - result = prime * result + this.reserved; - result = prime * result + this.masklen; - result = prime * result + this.addr.hashCode(); - return result; - } - - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals() - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof PIMAddrGroup)) { - return false; - } - final PIMAddrGroup other = (PIMAddrGroup) obj; - if (this.family != other.family) { - return false; - } - - if (this.encType != other.encType) { - return false; - } - - if (!this.addr.equals(other.addr)) { - return false; - } - return true; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java deleted file mode 100644 index 762dad56..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrSource.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet.pim; - -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Ip4Address; -import org.onlab.packet.Ip6Address; -import org.onlab.packet.IpAddress; -import org.onlab.packet.IpPrefix; -import org.onlab.packet.PIM; - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.checkInput; - -public class PIMAddrSource { - private byte family; - private byte encType; - private byte reserved; - private boolean sBit; - private boolean wBit; - private boolean rBit; - private byte masklen; - IpAddress addr; - - public static final int ENC_SOURCE_IPV4_BYTE_LENGTH = 4 + Ip4Address.BYTE_LENGTH; - public static final int ENC_SOURCE_IPV6_BYTE_LENGTH = 4 + Ip6Address.BYTE_LENGTH; - - /** - * PIM Encoded Source Address. - * - * @param addr IPv4 or IPv6 - */ - public PIMAddrSource(String addr) { - this.init(); - this.setAddr(addr); - } - - /** - * PIM Encoded Source Address. - * - * @param spfx IPv4 or IPv6 - */ - public PIMAddrSource(IpPrefix spfx) { - this.init(); - this.setAddr(spfx); - } - - /** - * PIM Encoded Group Address. - */ - public PIMAddrSource() { - this.init(); - } - - private void init() { - this.family = PIM.ADDRESS_FAMILY_IP4; - this.encType = 0; - this.reserved = 0; - this.sBit = true; - this.wBit = false; - this.rBit = false; - } - - /** - * PIM Encoded Source Address. - * - * @param addr IPv4 or IPv6 - */ - public void setAddr(String addr) { - IpPrefix spfx = IpPrefix.valueOf(addr); - setAddr(spfx); - } - - /** - * PIM Encoded Source Address. - * - * @param spfx IPv4 or IPv6 address prefix - */ - public void setAddr(IpPrefix spfx) { - this.addr = spfx.address(); - this.masklen = (byte) spfx.prefixLength(); - this.family = (byte) ((this.addr.isIp4()) ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6); - } - - /** - * Get the IP family of this address: 4 or 6. - * - * @return the IP address family - */ - public byte getFamily() { - return this.family; - } - - /** - * Get the address of this encoded address. - * - * @return source address - */ - public IpAddress getAddr() { - return this.addr; - } - - /** - * Get the masklen of the group address. - * - * @return the masklen - */ - public int getMasklen() { - return this.masklen; - } - - /** - * Return the sparse bit. - * - * @return true or false - */ - public boolean getSBit() { - return this.sBit; - } - - /** - * Return the wBit, used in Join/Prune messages. - * - * @return return true or false. - */ - public boolean getWBit() { - return this.wBit; - } - - /** - * Return the rBit. Used by Rendezvous Point. - * - * @return the rBit. - */ - public boolean getRBit() { - return this.rBit; - } - - /** - * The size in bytes of a serialized address. - * - * @return the number of bytes when serialized - */ - public int getByteSize() { - int size = 4; - size += addr.isIp4() ? PIM.ADDRESS_FAMILY_IP4 : PIM.ADDRESS_FAMILY_IP6; - return size; - } - - public byte[] serialize() { - int len = addr.isIp4() ? ENC_SOURCE_IPV4_BYTE_LENGTH : ENC_SOURCE_IPV6_BYTE_LENGTH; - - final byte[] data = new byte[len]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(this.family); - bb.put(this.encType); - - // Todo: technically we should be setting the B and Z bits, but we'll never use them. - byte mask = 0x0; - if (this.sBit) { - this.reserved |= 0x4; - } - if (this.wBit) { - this.reserved |= 0x2; - } - if (this.rBit) { - this.reserved |= 0x1; - } - bb.put(reserved); - - bb.put(this.masklen); - bb.put(this.addr.toOctets()); - return data; - } - - public PIMAddrSource deserialize(byte[] data, int offset, int length) throws DeserializationException { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - return deserialize(bb); - } - - public PIMAddrSource deserialize(ByteBuffer bb) throws DeserializationException { - - /* - * We need to verify that we have enough buffer space. First we'll assume that - * we are decoding an IPv4 address. After we read the first by (address family), - * we'll determine if we actually need more buffer space for an IPv6 address. - */ - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV4_BYTE_LENGTH); - - this.family = bb.get(); - if (family != PIM.ADDRESS_FAMILY_IP4 && family != PIM.ADDRESS_FAMILY_IP6) { - throw new DeserializationException("Illegal IP version number: " + family + "\n"); - } else if (family == PIM.ADDRESS_FAMILY_IP6) { - - // Check for one less by since we have already read the first byte of the packet. - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_SOURCE_IPV6_BYTE_LENGTH - 1); - } - - this.encType = bb.get(); - this.reserved = bb.get(); - if ((this.reserved & 0x01) != 0) { - this.rBit = true; - } - if ((this.reserved & 0x02) != 0) { - this.wBit = true; - } - if ((this.reserved & 0x4) != 0) { - this.sBit = true; - } - - // Remove the s, reserved - this.reserved &= 0xf8; - - this.masklen = bb.get(); - if (this.family == PIM.ADDRESS_FAMILY_IP4) { - this.addr = IpAddress.valueOf(bb.getInt()); - } else if (this.family == PIM.ADDRESS_FAMILY_IP6) { - this.addr = Ip6Address.valueOf(bb.array(), 2); - } - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - result = prime * result + this.family; - result = prime * result + this.encType; - result = prime * result + this.reserved; - result = prime * result + this.masklen; - result = prime * result + this.addr.hashCode(); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof PIMAddrSource)) { - return false; - } - final PIMAddrSource other = (PIMAddrSource) obj; - if (this.family != other.family) { - return false; - } - - if (this.encType != other.encType) { - return false; - } - - if (!this.addr.equals(other.addr)) { - return false; - } - return true; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java deleted file mode 100644 index 3327a8e7..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMAddrUnicast.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet.pim; - - - -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Ip4Address; -import org.onlab.packet.Ip6Address; -import org.onlab.packet.IpAddress; -import org.onlab.packet.PIM; - -import java.nio.ByteBuffer; - -import static org.onlab.packet.PacketUtils.checkInput; - -public class PIMAddrUnicast { - private byte family; - private byte encType; - IpAddress addr; - - public static final int ENC_UNICAST_IPV4_BYTE_LENGTH = 2 + Ip4Address.BYTE_LENGTH; - public static final int ENC_UNICAST_IPV6_BYTE_LENGTH = 2 + Ip6Address.BYTE_LENGTH; - - /** - * PIM Encoded Source Address. - */ - public PIMAddrUnicast() { - this.family = PIM.ADDRESS_FAMILY_IP4; - this.encType = 0; - } - - /** - * PIM Encoded Source Address. - * - * @param addr IPv4 or IPv6 - */ - public PIMAddrUnicast(String addr) { - this.addr = IpAddress.valueOf(addr); - if (this.addr.isIp4()) { - this.family = PIM.ADDRESS_FAMILY_IP4; - } else { - this.family = PIM.ADDRESS_FAMILY_IP6; - } - this.encType = 0; - } - - /** - * PIM Encoded Source Address. - * - * @param addr IPv4 or IPv6 - */ - public void setAddr(IpAddress addr) { - this.addr = addr; - if (this.addr.isIp4()) { - this.family = PIM.ADDRESS_FAMILY_IP4; - } else { - this.family = PIM.ADDRESS_FAMILY_IP6; - } - } - - /** - * Get the address of this encoded address. - * - * @return source address - */ - public IpAddress getAddr() { - return this.addr; - } - - /** - * Get the IP family of this address: 4 or 6. - * - * @return the IP address family - */ - public int getFamily() { - return this.family; - } - - /** - * The size in bytes of a serialized address. - * - * @return the number of bytes when serialized - */ - public int getByteSize() { - int size = 2; - if (addr != null) { - size += addr.isIp4() ? 4 : 16; - } else { - size += 4; - } - return size; - } - - public byte[] serialize() { - int len = getByteSize(); - - final byte[] data = new byte[len]; - final ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(family); - bb.put(encType); - bb.put(addr.toOctets()); - return data; - } - - public PIMAddrUnicast deserialize(ByteBuffer bb) throws DeserializationException { - - // Assume IPv4 for check length until we read the encoded family. - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_UNICAST_IPV4_BYTE_LENGTH); - this.family = bb.get(); - - // If we have IPv6 we need to ensure we have adequate buffer space. - if (this.family != PIM.ADDRESS_FAMILY_IP4 && this.family != PIM.ADDRESS_FAMILY_IP6) { - throw new DeserializationException("Invalid address family: " + this.family); - } else if (this.family == PIM.ADDRESS_FAMILY_IP6) { - // Subtract -1 from ENC_UNICAST_IPv6 BYTE_LENGTH because we read one byte for family previously. - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), ENC_UNICAST_IPV6_BYTE_LENGTH - 1); - } - - this.encType = bb.get(); - if (this.family == PIM.ADDRESS_FAMILY_IP4) { - this.addr = IpAddress.valueOf(bb.getInt()); - } else if (this.family == PIM.ADDRESS_FAMILY_IP6) { - this.addr = Ip6Address.valueOf(bb.array(), 2); - } - return this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 2521; - int result = super.hashCode(); - result = prime * result + this.family; - result = prime * result + this.encType; - result = prime * result + this.addr.hashCode(); - return result; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof PIMAddrUnicast)) { - return false; - } - final PIMAddrUnicast other = (PIMAddrUnicast) obj; - if (this.family != other.family) { - return false; - } - - if (this.encType != other.encType) { - return false; - } - - if (!this.addr.equals(other.addr)) { - return false; - } - return true; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java deleted file mode 100644 index 9ad3fdbd..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet.pim; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.IpAddress; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; - -import static org.onlab.packet.PacketUtils.checkInput; - -public class PIMHello extends BasePacket { - - private IpAddress nbrIpAddress; - private boolean priorityPresent = false; - - private Map<Short, PIMHelloOption> options = new HashMap<>(); - - /** - * Create a PIM Hello packet with the most common hello options and default - * values. The values of any options can be easily changed by modifying the value of - * the option with the desired change. - */ - public void createDefaultOptions() { - options.put(PIMHelloOption.OPT_HOLDTIME, new PIMHelloOption(PIMHelloOption.OPT_HOLDTIME)); - options.put(PIMHelloOption.OPT_PRIORITY, new PIMHelloOption(PIMHelloOption.OPT_PRIORITY)); - options.put(PIMHelloOption.OPT_GENID, new PIMHelloOption(PIMHelloOption.OPT_GENID)); - } - - /** - * Add a PIM Hello option to this hello message. Note - * - * @param opt the PIM Hello option we are adding - */ - public void addOption(PIMHelloOption opt) { - this.options.put(opt.getOptType(), opt); - } - - public Map<Short, PIMHelloOption> getOptions() { - return this.options; - } - - /** - * Sets all payloads parent packet if applicable, then serializes this - * packet and all payloads. - * - * @return a byte[] containing this packet and payloads - */ - @Override - public byte[] serialize() { - int totalLen = 0; - - - // Since we are likely to only have 3-4 options, go head and walk the - // hashmap twice, once to calculate the space needed to allocate a - // buffer, the second time serialize the options into the buffer. This - // saves us from allocating an over sized buffer the re-allocating and - // copying. - for (Short optType : options.keySet()) { - PIMHelloOption opt = options.get(optType); - totalLen += PIMHelloOption.MINIMUM_OPTION_LEN_BYTES + opt.getOptLength(); - } - - byte[] data = new byte[totalLen]; - ByteBuffer bb = ByteBuffer.wrap(data); - - // Now serialize the data. - for (Short optType : options.keySet()) { - PIMHelloOption opt = options.get(optType); - bb.put(opt.serialize()); - } - return data; - } - - /** - * XXX: This is deprecated, DO NOT USE, use the deserializer() function instead. - */ - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - // TODO: throw an expection? - return null; - } - - /** - * Deserialize this hello message. - * - * @return a deserialized hello message - */ - public static Deserializer<PIMHello> deserializer() { - return (data, offset, length) -> { - checkInput(data, offset, length, PIMHelloOption.MINIMUM_OPTION_LEN_BYTES); - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - PIMHello hello = new PIMHello(); - while (bb.hasRemaining()) { - PIMHelloOption opt = PIMHelloOption.deserialize(bb); - hello.addOption(opt); - } - return hello; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMHelloOption.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMHelloOption.java deleted file mode 100644 index bf021fbd..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMHelloOption.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet.pim; - -import org.onlab.packet.DeserializationException; - -import java.nio.ByteBuffer; -import java.text.MessageFormat; - -import static org.onlab.packet.PacketUtils.checkBufferLength; -import static org.onlab.packet.PacketUtils.checkInput; - -public class PIMHelloOption { - - /** - * PIM Option types. - */ - public static final short OPT_HOLDTIME = 1; - public static final short OPT_PRUNEDELAY = 2; - public static final short OPT_PRIORITY = 19; - public static final short OPT_GENID = 20; - public static final short OPT_ADDRLIST = 24; - - public static final short DEFAULT_HOLDTIME = 105; - public static final int DEFAULT_PRUNEDELAY = 2000; // 2,000 ms - public static final int DEFAULT_PRIORITY = 1; - public static final int DEFAULT_GENID = 0; - - public static final int MINIMUM_OPTION_LEN_BYTES = 4; - - // Values for this particular hello option. - private short optType; - private short optLength; - private byte[] optValue; - - public PIMHelloOption() { - } - - /** - * Set a PIM Hello option by type. The length and default value of the - * type will be auto filled in by default. - * - * @param type hello option type - */ - public PIMHelloOption(short type) { - this.optType = type; - switch (type) { - case OPT_HOLDTIME: - this.optLength = 2; - this.optValue = new byte[optLength]; - ByteBuffer.wrap(this.optValue).putShort(PIMHelloOption.DEFAULT_HOLDTIME); - break; - - case OPT_PRUNEDELAY: - this.optLength = 4; - this.optValue = new byte[this.optLength]; - ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRUNEDELAY); - break; - - case OPT_PRIORITY: - this.optLength = 4; - this.optValue = new byte[this.optLength]; - ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRIORITY); - break; - - case OPT_GENID: - this.optLength = 4; - this.optValue = new byte[this.optLength]; - ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_GENID); - break; - - case OPT_ADDRLIST: - this.optLength = 0; // We don't know what the length will be yet. - this.optValue = null; - - default: - //log.error("Unkown option type: " + type + "\n" ); - return; - } - } - - public void setOptType(short type) { - this.optType = type; - } - - public short getOptType() { - return this.optType; - } - - public void setOptLength(short len) { - this.optLength = len; - } - - public short getOptLength() { - return this.optLength; - } - - public void setValue(ByteBuffer bb) throws DeserializationException { - this.optValue = new byte[this.optLength]; - bb.get(this.optValue, 0, this.optLength); - } - - public byte[] getValue() { - return this.optValue; - } - - public static PIMHelloOption deserialize(ByteBuffer bb) throws DeserializationException { - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4); - - PIMHelloOption opt = new PIMHelloOption(); - opt.setOptType(bb.getShort()); - opt.setOptLength(bb.getShort()); - - checkBufferLength(bb.limit(), bb.position(), opt.getOptLength()); - opt.setValue(bb); - - return opt; - } - - public byte [] serialize() { - int len = 4 + this.optLength; - ByteBuffer bb = ByteBuffer.allocate(len); - bb.putShort(this.optType); - bb.putShort(this.optLength); - bb.put(this.optValue); - return bb.array(); - } - - public String toString() { - return MessageFormat.format("Type: {0}, len: {1} value: {2}", this.optType, this.optLength, - (this.optValue == null) ? "null" : this.optValue.toString()); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java deleted file mode 100644 index 9653115b..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/PIMJoinPrune.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet.pim; - -import org.onlab.packet.BasePacket; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPacket; -import org.onlab.packet.IpPrefix; - -import java.nio.ByteBuffer; -import java.util.HashMap; - -import static org.onlab.packet.PacketUtils.checkInput; - -public class PIMJoinPrune extends BasePacket { - - private PIMAddrUnicast upstreamAddr = new PIMAddrUnicast(); - private short holdTime = (short) 0xffff; - - private class JoinPruneGroup { - protected IpPrefix group; - protected HashMap<IpPrefix, IpPrefix> joins = new HashMap<>(); - protected HashMap<IpPrefix, IpPrefix> prunes = new HashMap<>(); - - public JoinPruneGroup(IpPrefix grp) { - group = grp; - } - } - private HashMap<IpPrefix, JoinPruneGroup> joinPrunes = new HashMap<>(); - - /** - * Get the J/P hold time. - * - * @return specified in seconds. - */ - public short getHoldTime() { - return holdTime; - } - - /** - * Set the J/P holdtime in seconds. - * - * @param holdTime return the holdtime. - */ - public void setHoldTime(short holdTime) { - this.holdTime = holdTime; - } - - /** - * Get the upstreamAddr for this J/P request. - * - * @return the upstream address. - */ - public PIMAddrUnicast getUpstreamAddr() { - return upstreamAddr; - } - - /** - * Set the upstream address of this PIM J/P request. - * - * @param upstr the PIM Upstream unicast address - */ - public void setUpstreamAddr(PIMAddrUnicast upstr) { - this.upstreamAddr = upstr; - } - - /** - * Add the specified s,g to join field. - * - * @param saddr the source address of the route - * @param gaddr the group address of the route - * @param join true for a join, false for a prune. - */ - public void addJoinPrune(String saddr, String gaddr, boolean join) { - IpPrefix gpfx = IpPrefix.valueOf(gaddr); - IpPrefix spfx = IpPrefix.valueOf(saddr); - addJoinPrune(spfx, gpfx, join); - } - - /** - * Add the specified S, G to the join field. - * - * @param spfx the source prefix of the route - * @param gpfx the group prefix of the route - * @param join true for join, false for prune - */ - public void addJoinPrune(IpPrefix spfx, IpPrefix gpfx, boolean join) { - JoinPruneGroup jpg = joinPrunes.get(gpfx); - if (jpg == null) { - jpg = new JoinPruneGroup(gpfx); - joinPrunes.put(gpfx, jpg); - } - - HashMap<IpPrefix, IpPrefix> members = (join) ? jpg.joins : jpg.prunes; - if (members.get(spfx) == null) { - members.put(spfx, spfx); - } - } - - /** - * Add a join given strings represending the source and group addresses. - * - * @param saddr source address - * @param gaddr group address - */ - public void addJoin(String saddr, String gaddr) { - this.addJoinPrune(saddr, gaddr, true); - } - - /** - * Add a prune given strings represending the source and group addresses. - * - * @param saddr source address - * @param gaddr group address - */ - public void addPrune(String saddr, String gaddr) { - this.addJoinPrune(saddr, gaddr, false); - } - - /** - * Sets all payloads parent packet if applicable, then serializes this - * packet and all payloads. - * - * @return a byte[] containing this packet and payloads - */ - @Override - public byte[] serialize() { - - byte[] data = new byte[8096]; // Come up with something better - ByteBuffer bb = ByteBuffer.wrap(data); - - bb.put(upstreamAddr.serialize()); - bb.put((byte) 0); // reserved - - int ngrps = joinPrunes.size(); - bb.put((byte) ngrps); - bb.putShort(this.holdTime); - - // Walk the group list and input all groups - for (JoinPruneGroup jpg : joinPrunes.values()) { - PIMAddrGroup grp = new PIMAddrGroup(jpg.group); - bb.put(grp.serialize()); - - // put the number of joins and prunes - bb.putShort((short) jpg.joins.size()); - bb.putShort((short) jpg.prunes.size()); - - // Set all of the joins - for (IpPrefix spfx : jpg.joins.values()) { - PIMAddrSource src = new PIMAddrSource(spfx); - bb.put(src.serialize()); - } - - // Set all of the prunes - for (IpPrefix spfx : jpg.prunes.values()) { - PIMAddrSource src = new PIMAddrSource(spfx); - bb.put(src.serialize()); - } - } - - int len = bb.position(); - byte[] data2 = new byte[len]; - bb = ByteBuffer.wrap(data2, 0, len); - bb.put(data, 0, len); - return data2; - } - - // TODO: I suppose I really need to implement this? - @Override - public IPacket deserialize(final byte[] data, final int offset, - final int length) { - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - return this; - } - - /** - * Return the J/P deserializer function. - * - * @return a function that will deserialize a J/P message. - */ - public static Deserializer<PIMJoinPrune> deserializer() { - return (data, offset, length) -> { - - /* - * Delay buffer checks until we read enough of the packet to know how - * much data we will require. Each encoded address deserializer function - * will ensure there is enough data for that address. - */ - PIMJoinPrune jp = new PIMJoinPrune(); - final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); - - // We must get a PIM encoded unicast address - PIMAddrUnicast upstream = new PIMAddrUnicast(); - upstream.deserialize(bb); - jp.setUpstreamAddr(upstream); - - // Use this boolean to determine the buffer space we need according to address sizes - boolean ipv4 = upstream.getAddr().isIp4(); - - // We need at minimum 4 bytes for reserved(1), ngroups(1) & holdtime(2) - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4); - - // get and skip the reserved byte - bb.get(); - - // Get the number of groups. - int ngroups = bb.get(); - - // Save the holdtime. - jp.setHoldTime(bb.getShort()); - - - for (int i = 0; i < ngroups; i++) { - PIMAddrGroup grp = new PIMAddrGroup(); - - /* - * grp.deserialize will ensure the buffer has enough data to read the group address. - */ - grp.deserialize(bb); - - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4); - int njoins = bb.getShort(); - int nprunes = bb.getShort(); - - /* - * Now we'll verify we have enough buffer to read the next - * group of join and prune addresses for this group. - */ - int required = (njoins + nprunes) * - (ipv4 ? PIMAddrSource.ENC_SOURCE_IPV4_BYTE_LENGTH : PIMAddrSource.ENC_SOURCE_IPV6_BYTE_LENGTH); - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), required); - - // Now iterate through the joins for this group - for (; njoins > 0; njoins--) { - - PIMAddrSource src = new PIMAddrSource(); - src.deserialize(bb); - - jp.addJoinPrune( - src.getAddr().toIpPrefix(), - grp.getAddr().toIpPrefix(), true); - } - - // Now iterate through the prunes for this group - for (; nprunes > 0; nprunes--) { - - PIMAddrSource src = new PIMAddrSource(); - src.deserialize(bb); - jp.addJoinPrune( - src.getAddr().toIpPrefix(), - grp.getAddr().toIpPrefix(), false); - } - } - - return jp; - }; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/package-info.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/package-info.java deleted file mode 100755 index 88a1ad5d..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/pim/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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. - */ - -/** - * Utilities for managing PIM packets. - */ -package org.onlab.packet.pim; - diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/AbstractAccumulator.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/AbstractAccumulator.java deleted file mode 100644 index 500f8d60..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/AbstractAccumulator.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.collect.Lists; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Base implementation of an item accumulator. It allows triggering based on - * item inter-arrival time threshold, maximum batch life threshold and maximum - * batch size. - */ -public abstract class AbstractAccumulator<T> implements Accumulator<T> { - - private Logger log = LoggerFactory.getLogger(AbstractAccumulator.class); - - private final Timer timer; - private final int maxItems; - private final int maxBatchMillis; - private final int maxIdleMillis; - - private volatile TimerTask idleTask = new ProcessorTask(); - private volatile TimerTask maxTask = new ProcessorTask(); - - private List<T> items = Lists.newArrayList(); - - /** - * Creates an item accumulator capable of triggering on the specified - * thresholds. - * - * @param timer timer to use for scheduling check-points - * @param maxItems maximum number of items to accumulate before - * processing is triggered - * @param maxBatchMillis maximum number of millis allowed since the first - * item before processing is triggered - * @param maxIdleMillis maximum number millis between items before - * processing is triggered - */ - protected AbstractAccumulator(Timer timer, int maxItems, - int maxBatchMillis, int maxIdleMillis) { - this.timer = checkNotNull(timer, "Timer cannot be null"); - - checkArgument(maxItems > 1, "Maximum number of items must be > 1"); - checkArgument(maxBatchMillis > 0, "Maximum millis must be positive"); - checkArgument(maxIdleMillis > 0, "Maximum idle millis must be positive"); - - this.maxItems = maxItems; - this.maxBatchMillis = maxBatchMillis; - this.maxIdleMillis = maxIdleMillis; - } - - @Override - public synchronized void add(T item) { - idleTask = cancelIfActive(idleTask); - items.add(checkNotNull(item, "Item cannot be null")); - - // Did we hit the max item threshold? - if (items.size() >= maxItems) { - maxTask = cancelIfActive(maxTask); - scheduleNow(); - } else { - // Otherwise, schedule idle task and if this is a first item - // also schedule the max batch age task. - idleTask = schedule(maxIdleMillis); - if (items.size() == 1) { - maxTask = schedule(maxBatchMillis); - } - } - } - - /** - * Finalizes the current batch, if ready, and schedules a new processor - * in the immediate future. - */ - private void scheduleNow() { - if (isReady()) { - TimerTask task = new ProcessorTask(finalizeCurrentBatch()); - timer.schedule(task, 1); - } - } - - /** - * Schedules a new processor task given number of millis in the future. - * Batch finalization is deferred to time of execution. - */ - private TimerTask schedule(int millis) { - TimerTask task = new ProcessorTask(); - timer.schedule(task, millis); - return task; - } - - /** - * Cancels the specified task if it is active. - */ - private TimerTask cancelIfActive(TimerTask task) { - if (task != null) { - task.cancel(); - } - return task; - } - - // Task for triggering processing of accumulated items - private class ProcessorTask extends TimerTask { - - private final List<T> items; - - // Creates a new processor task with deferred batch finalization. - ProcessorTask() { - this.items = null; - } - - // Creates a new processor task with pre-emptive batch finalization. - ProcessorTask(List<T> items) { - this.items = items; - } - - @Override - public void run() { - synchronized (AbstractAccumulator.this) { - idleTask = cancelIfActive(idleTask); - } - if (isReady()) { - try { - synchronized (AbstractAccumulator.this) { - maxTask = cancelIfActive(maxTask); - } - List<T> batch = items != null ? items : finalizeCurrentBatch(); - if (!batch.isEmpty()) { - processItems(batch); - } - } catch (Exception e) { - log.warn("Unable to process batch due to", e); - } - } else { - synchronized (AbstractAccumulator.this) { - idleTask = schedule(maxIdleMillis); - } - } - } - } - - // Demotes and returns the current batch of items and promotes a new one. - private synchronized List<T> finalizeCurrentBatch() { - List<T> toBeProcessed = items; - items = Lists.newArrayList(); - return toBeProcessed; - } - - @Override - public boolean isReady() { - return true; - } - - /** - * Returns the backing timer. - * - * @return backing timer - */ - public Timer timer() { - return timer; - } - - /** - * Returns the maximum number of items allowed to accumulate before - * processing is triggered. - * - * @return max number of items - */ - public int maxItems() { - return maxItems; - } - - /** - * Returns the maximum number of millis allowed to expire since the first - * item before processing is triggered. - * - * @return max number of millis a batch is allowed to last - */ - public int maxBatchMillis() { - return maxBatchMillis; - } - - /** - * Returns the maximum number of millis allowed to expire since the last - * item arrival before processing is triggered. - * - * @return max number of millis since the last item - */ - public int maxIdleMillis() { - return maxIdleMillis; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Accumulator.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Accumulator.java deleted file mode 100644 index 20b7a481..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Accumulator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.List; - -/** - * Abstraction of an accumulator capable of collecting items and at some - * point in time triggers processing of all previously accumulated items. - * - * @param <T> item type - */ -public interface Accumulator<T> { - - /** - * Adds an item to the current batch. This operation may, or may not - * trigger processing of the current batch of items. - * - * @param item item to be added to the current batch - */ - void add(T item); - - /** - * Processes the specified list of accumulated items. - * - * @param items list of accumulated items - */ - void processItems(List<T> items); - - /** - * Indicates whether the accumulator is ready to process items. - * - * @return true if ready to process - */ - boolean isReady(); -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java deleted file mode 100644 index 60806568..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Bandwidth.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.collect.ComparisonChain; - -import java.util.Objects; - -/** - * Representation of bandwidth. - * Use the static factory method corresponding to the unit (like Kbps) you desire on instantiation. - */ -public final class Bandwidth implements RichComparable<Bandwidth> { - - private final double bps; - - /** - * Creates a new instance with given bandwidth. - * - * @param bps bandwidth value to be assigned - */ - private Bandwidth(double bps) { - this.bps = bps; - } - - // Constructor for serialization - private Bandwidth() { - this.bps = 0; - } - - /** - * Creates a new instance with given bandwidth. - * - * @param v bandwidth value - * @param unit {@link DataRateUnit} of {@code v} - * @return {@link Bandwidth} instance with given bandwidth - */ - public static Bandwidth of(double v, DataRateUnit unit) { - return new Bandwidth(unit.toBitsPerSecond(v)); - } - - /** - * Creates a new instance with given bandwidth in bps. - * - * @param bps bandwidth value to be assigned - * @return {@link Bandwidth} instance with given bandwidth - */ - public static Bandwidth bps(double bps) { - return new Bandwidth(bps); - } - - /** - * Creates a new instance with given bandwidth in Kbps. - * - * @param kbps bandwidth value to be assigned - * @return {@link Bandwidth} instance with given bandwidth - */ - public static Bandwidth kbps(double kbps) { - return bps(kbps * 1_000L); - } - - /** - * Creates a new instance with given bandwidth in Mbps. - * - * @param mbps bandwidth value to be assigned - * @return {@link Bandwidth} instance with given bandwidth - */ - public static Bandwidth mbps(double mbps) { - return bps(mbps * 1_000_000L); - } - - /** - * Creates a new instance with given bandwidth in Gbps. - * - * @param gbps bandwidth value to be assigned - * @return {@link Bandwidth} instance with given bandwidth - */ - public static Bandwidth gbps(double gbps) { - return bps(gbps * 1_000_000_000L); - } - - /** - * Returns bandwidth in bps. - * - * @return bandwidth in bps. - */ - public double bps() { - return bps; - } - - /** - * Returns a Bandwidth whose value is (this + value). - * - * @param value value to be added to this Frequency - * @return this + value - */ - public Bandwidth add(Bandwidth value) { - return bps(this.bps + value.bps); - } - - /** - * Returns a Bandwidth whose value is (this - value). - * - * @param value value to be added to this Frequency - * @return this - value - */ - public Bandwidth subtract(Bandwidth value) { - return bps(this.bps - value.bps); - } - - @Override - public int compareTo(Bandwidth other) { - return ComparisonChain.start() - .compare(this.bps, other.bps) - .result(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Bandwidth) { - Bandwidth that = (Bandwidth) obj; - return Objects.equals(this.bps, that.bps); - } - return false; - } - - @Override - public int hashCode() { - return Long.hashCode(Double.doubleToLongBits(bps)); - } - - @Override - public String toString() { - return String.valueOf(this.bps); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/BlockingBoolean.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/BlockingBoolean.java deleted file mode 100644 index f3049c31..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/BlockingBoolean.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.AbstractQueuedSynchronizer; - -/** - * Mutable boolean that allows threads to wait for a specified value. - */ -public class BlockingBoolean extends AbstractQueuedSynchronizer { - - private static final int TRUE = 1; - private static final int FALSE = 0; - - /** - * Creates a new blocking boolean with the specified value. - * - * @param value the starting value - */ - public BlockingBoolean(boolean value) { - setState(value ? TRUE : FALSE); - } - - /** - * Causes the current thread to wait until the boolean equals the specified - * value unless the thread is {@linkplain Thread#interrupt interrupted}. - * - * @param value specified value - * @throws InterruptedException if interrupted while waiting - */ - public void await(boolean value) throws InterruptedException { - acquireSharedInterruptibly(value ? TRUE : FALSE); - } - - /** - * Causes the current thread to wait until the boolean equals the specified - * value unless the thread is {@linkplain Thread#interrupt interrupted}, - * or the specified waiting time elapses. - * - * @param value specified value - * @param timeout the maximum time to wait - * @param unit the time unit of the {@code timeout} argument - * @return {@code true} if the count reached zero and {@code false} - * if the waiting time elapsed before the count reached zero - * @throws InterruptedException if interrupted while waiting - */ - public boolean await(boolean value, long timeout, TimeUnit unit) - throws InterruptedException { - return tryAcquireSharedNanos(value ? TRUE : FALSE, unit.toNanos(timeout)); - } - - protected int tryAcquireShared(int acquires) { - return (getState() == acquires) ? 1 : -1; - } - - /** - * Sets the value of the blocking boolean. - * - * @param value new value - */ - public void set(boolean value) { - releaseShared(value ? TRUE : FALSE); - } - - /** - * Gets the value of the blocking boolean. - * - * @return current value - */ - public boolean get() { - return getState() == TRUE; - } - - protected boolean tryReleaseShared(int releases) { - // Signal on state change only - int state = getState(); - if (state == releases) { - return false; - } - return compareAndSetState(state, releases); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/BoundedThreadPool.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/BoundedThreadPool.java deleted file mode 100644 index 9eef6609..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/BoundedThreadPool.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.slf4j.LoggerFactory; - -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Implementation of ThreadPoolExecutor that bounds the work queue. - * <p> - * When a new job would exceed the queue bound, the job is run on the caller's - * thread rather than on a thread from the pool. - * </p> - */ -public final class BoundedThreadPool extends ThreadPoolExecutor { - - private static final org.slf4j.Logger log = LoggerFactory.getLogger(BoundedThreadPool.class); - - protected static int maxQueueSize = 80_000; //TODO tune this value - //private static final RejectedExecutionHandler DEFAULT_HANDLER = new CallerFeedbackPolicy(); - private static final long STATS_INTERVAL = 5_000; //ms - - private final BlockingBoolean underHighLoad; - - private BoundedThreadPool(int numberOfThreads, - ThreadFactory threadFactory) { - super(numberOfThreads, numberOfThreads, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue<>(maxQueueSize), - threadFactory, - new CallerFeedbackPolicy()); - underHighLoad = ((CallerFeedbackPolicy) getRejectedExecutionHandler()).load(); - } - - /** - * Returns a single-thread, bounded executor service. - * - * @param threadFactory thread factory for the worker thread. - * @return the bounded thread pool - */ - public static BoundedThreadPool newSingleThreadExecutor(ThreadFactory threadFactory) { - return new BoundedThreadPool(1, threadFactory); - } - - /** - * Returns a fixed-size, bounded executor service. - * - * @param numberOfThreads number of threads in the pool - * @param threadFactory thread factory for the worker threads. - * @return the bounded thread pool - */ - public static BoundedThreadPool newFixedThreadPool(int numberOfThreads, ThreadFactory threadFactory) { - return new BoundedThreadPool(numberOfThreads, threadFactory); - } - - //TODO Might want to switch these to use Metrics class Meter and/or Gauge instead. - private final Counter submitted = new Counter(); - private final Counter taken = new Counter(); - - @Override - public Future<?> submit(Runnable task) { - submitted.add(1); - return super.submit(task); - } - - @Override - public <T> Future<T> submit(Runnable task, T result) { - submitted.add(1); - return super.submit(task, result); - } - - @Override - public void execute(Runnable command) { - submitted.add(1); - super.execute(command); - } - - @Override - public <T> Future<T> submit(Callable<T> task) { - submitted.add(1); - return super.submit(task); - } - - - @Override - protected void beforeExecute(Thread t, Runnable r) { - super.beforeExecute(t, r); - taken.add(1); - periodicallyPrintStats(); - updateLoad(); - } - - // TODO schedule this with a fixed delay from a scheduled executor - private final AtomicLong lastPrinted = new AtomicLong(0L); - - private void periodicallyPrintStats() { - long now = System.currentTimeMillis(); - long prev = lastPrinted.get(); - if (now - prev > STATS_INTERVAL) { - if (lastPrinted.compareAndSet(prev, now)) { - log.debug("queue size: {} jobs, submitted: {} jobs/s, taken: {} jobs/s", - getQueue().size(), - submitted.throughput(), taken.throughput()); - submitted.reset(); - taken.reset(); - } - } - } - - // TODO consider updating load whenever queue changes - private void updateLoad() { - underHighLoad.set(getQueue().remainingCapacity() / (double) maxQueueSize < 0.2); - } - - /** - * Feedback policy that delays the caller's thread until the executor's work - * queue falls below a threshold, then runs the job on the caller's thread. - */ - private static final class CallerFeedbackPolicy implements RejectedExecutionHandler { - - private final BlockingBoolean underLoad = new BlockingBoolean(false); - - public BlockingBoolean load() { - return underLoad; - } - - /** - * Executes task r in the caller's thread, unless the executor - * has been shut down, in which case the task is discarded. - * - * @param r the runnable task requested to be executed - * @param e the executor attempting to execute this task - */ - public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { - if (!e.isShutdown()) { - // Wait for up to 1 second while the queue drains... - boolean notified = false; - try { - notified = underLoad.await(false, 1, TimeUnit.SECONDS); - } catch (InterruptedException exception) { - log.debug("Got exception waiting for notification:", exception); - } finally { - if (!notified) { - log.info("Waited for 1 second on {}. Proceeding with work...", - Thread.currentThread().getName()); - } else { - log.info("FIXME we got a notice"); - } - } - // Do the work on the submitter's thread - r.run(); - } - } - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/ByteArraySizeHashPrinter.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/ByteArraySizeHashPrinter.java deleted file mode 100644 index cc39ce28..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/ByteArraySizeHashPrinter.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.Arrays; - -import com.google.common.base.MoreObjects; -import com.google.common.base.MoreObjects.ToStringHelper; - -/** - * Helper to print byte[] length and hashCode. - */ -public final class ByteArraySizeHashPrinter { - - private final byte[] bytes; - - /** - * Returns ByteArraySizeHashPrinter wrapping given byte[]. - * - * @param bytes bytes to wrap around - * @return ByteArraySizeHashPrinter - */ - public static ByteArraySizeHashPrinter of(byte[] bytes) { - return new ByteArraySizeHashPrinter(bytes); - } - - /** - * Returns ByteArraySizeHashPrinter wrapping given byte[]. - * - * @param bytes bytes to wrap around - * @return null if {@code bytes == null}, ByteArraySizeHashPrinter otherwise - */ - public static ByteArraySizeHashPrinter orNull(byte[] bytes) { - if (bytes == null) { - return null; - } - return new ByteArraySizeHashPrinter(bytes); - } - - public ByteArraySizeHashPrinter(byte[] bytes) { - this.bytes = bytes; - } - - @Override - public String toString() { - ToStringHelper helper = MoreObjects.toStringHelper("byte[]"); - if (bytes != null) { - helper.add("length", bytes.length) - .add("hash", Arrays.hashCode(bytes)); - } else { - helper.addValue(bytes); - } - return helper.toString(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Counter.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Counter.java deleted file mode 100644 index bde28783..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Counter.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; -import static com.google.common.base.Preconditions.checkArgument; - -/** - * Counting mechanism capable of tracking occurrences and rates. - */ -public class Counter { - - private long total = 0; - private long start = System.currentTimeMillis(); - private long end = 0; - - /** - * Creates a new counter. - */ - public Counter() { - } - - /** - * Creates a new counter in a specific state. If non-zero end time is - * specified, the counter will be frozen. - * - * @param start start time - * @param total total number of items to start with - * @param end end time; if non-ze - */ - public Counter(long start, long total, long end) { - checkArgument(start <= end, "Malformed interval: start > end"); - checkArgument(total >= 0, "Total must be non-negative"); - this.start = start; - this.total = total; - this.end = end; - } - - /** - * Resets the counter, by zeroing out the count and restarting the timer. - */ - public synchronized void reset() { - end = 0; - total = 0; - start = System.currentTimeMillis(); - } - - /** - * Freezes the counter in the current state including the counts and times. - */ - public synchronized void freeze() { - end = System.currentTimeMillis(); - } - - /** - * Adds the specified number of occurrences to the counter. No-op if the - * counter has been frozen. - * - * @param count number of occurrences - */ - public synchronized void add(long count) { - checkArgument(count >= 0, "Count must be non-negative"); - if (end == 0L) { - total += count; - } - } - - /** - * Returns the number of occurrences per second. - * - * @return throughput in occurrences per second - */ - public synchronized double throughput() { - return total / duration(); - } - - /** - * Returns the total number of occurrences counted. - * - * @return number of counted occurrences - */ - public synchronized long total() { - return total; - } - - /** - * Returns the duration expressed in fractional number of seconds. - * - * @return fractional number of seconds since the last reset - */ - public synchronized double duration() { - // Protect against 0 return by artificially setting duration to 1ms - long duration = (end == 0L ? System.currentTimeMillis() : end) - start; - return (duration == 0 ? 1 : duration) / 1000.0; - } - - @Override - public int hashCode() { - return Objects.hash(total, start, end); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof Counter) { - final Counter other = (Counter) obj; - return Objects.equals(this.total, other.total) && - Objects.equals(this.start, other.start) && - Objects.equals(this.end, other.end); - } - return false; - } - - @Override - public String toString() { - return toStringHelper(this) - .add("total", total) - .add("start", start) - .add("end", end) - .toString(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java deleted file mode 100644 index d49ed7b5..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DataRateUnit.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.onlab.util; - -import com.google.common.annotations.Beta; - -/** - * Data rate unit. - */ -@Beta -public enum DataRateUnit { - /** - * Bit per second. - */ - BPS(1L), - /** - * Kilobit per second. - * (Decimal/SI) - */ - KBPS(1_000L), - /** - * Megabit per second. - * (Decimal/SI) - */ - MBPS(1_000_000L), - /** - * Gigabit per second. - * (Decimal/SI) - */ - GBPS(1_000_000_000L); - - private final long multiplier; - - DataRateUnit(long multiplier) { - this.multiplier = multiplier; - } - - /** - * Returns the multiplier to use, when converting value of this unit to bps. - * - * @return multiplier - */ - public long multiplier() { - return multiplier; - } - - /** - * Converts given value in this unit to bits per seconds. - * - * @param v data rate value - * @return {@code v} in bits per seconds - */ - public long toBitsPerSecond(long v) { - return v * multiplier; - } - - /** - * Converts given value in this unit to bits per seconds. - * - * @param v data rate value - * @return {@code v} in bits per seconds - */ - public double toBitsPerSecond(double v) { - return v * multiplier; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DefaultHashMap.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DefaultHashMap.java deleted file mode 100644 index d6ddbd56..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/DefaultHashMap.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.HashMap; - -/** - * HashMap that returns a default value for unmapped keys. - */ -public final class DefaultHashMap<K, V> extends HashMap<K, V> { - - /** Default value to return when no key binding exists. */ - protected final V defaultValue; - - /** - * Constructs an empty map with the given default value. - * - * @param defaultValue the default value - */ - public DefaultHashMap(V defaultValue) { - this.defaultValue = defaultValue; - } - - @Override - public V get(Object k) { - return containsKey(k) ? super.get(k) : defaultValue; - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Frequency.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Frequency.java deleted file mode 100644 index 1ef71130..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Frequency.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.base.MoreObjects; -import com.google.common.collect.ComparisonChain; - -/** - * Class representing frequency. This class is intended to be used for a value whose unit is Hz - * and its family (KHz, MHz, etc.). - * - * <p> - * Note: this class is mainly intended to be used for lambda, which - * represents THz order. Long has enough space to represent over THz frequency as Hz, - * and the underlying value is long as Hz. This means this class can't represent - * sub-Hz accuracy. - * </p> - */ -public final class Frequency implements RichComparable<Frequency> { - - private static final long KHZ = 1_000L; - private static final long MHZ = 1_000_000L; - private static final long GHZ = 1_000_000_000L; - private static final long THZ = 1_000_000_000_000L; - - private final long frequency; // frequency in Hz - - /** - * Creates an instance representing the specified frequency in Hz. - * - * @param frequency frequency in Hz - */ - private Frequency(long frequency) { - this.frequency = frequency; - } - - /** - * Return the value this instance represents as Hz. - * - * @return frequency in Hz - */ - public long asHz() { - return frequency; - } - - /** - * Returns an instance representing the specified value in Hz. - * - * @param value frequency in Hz - * @return instance representing the given frequency - */ - public static Frequency ofHz(long value) { - return new Frequency(value); - } - - /** - * Returns an instance representing the specified value in KHz. - * - * @param value frequency in KHz - * @return instance representing the given frequency - */ - public static Frequency ofKHz(double value) { - return new Frequency((long) (value * KHZ)); - } - - /** - * Returns an instance representing the specified value in MHz. - * - * @param value frequency in MHz - * @return instance representing the given frequency - */ - public static Frequency ofMHz(double value) { - return new Frequency((long) (value * MHZ)); - } - - /** - * Returns an instance representing the specified value in GHz. - * - * @param value frequency in GHz - * @return instance representing the given frequency - */ - public static Frequency ofGHz(double value) { - return new Frequency((long) (value * GHZ)); - } - - /** - * Returns an instance representing the specified value in THz. - * - * @param value frequency in THz - * @return instance representing the given frequency - */ - public static Frequency ofTHz(double value) { - return new Frequency((long) (value * THZ)); - } - - /** - * Returns a Frequency whose value is (this + value). - * - * @param value value to be added to this Frequency - * @return this + value - */ - public Frequency add(Frequency value) { - return new Frequency(this.frequency + value.frequency); - } - - /** - * Returns a Frequency whose value is (this - value). - * - * @param value value to be subtracted from this Frequency - * @return this - value - */ - public Frequency subtract(Frequency value) { - return new Frequency(this.frequency - value.frequency); - } - - /** - * Returns a Frequency whose value is (this * value). - * - * @param value value to be multiplied by this Frequency - * @return this * value - */ - public Frequency multiply(long value) { - return new Frequency(this.frequency * value); - } - - /** - * Returns a Frequency whose value is Math.floorDiv(this, value). - * - * @param value value to be divided by this Frequency - * @return Math.floorDiv(this, value) - */ - public Frequency floorDivision(long value) { - return new Frequency(Math.floorDiv(this.frequency, value)); - } - - @Override - public int compareTo(Frequency other) { - return ComparisonChain.start() - .compare(this.frequency, other.frequency) - .result(); - } - - @Override - public int hashCode() { - return Long.hashCode(frequency); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (!(obj instanceof Frequency)) { - return false; - } - - final Frequency other = (Frequency) obj; - return this.frequency == other.frequency; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("frequency", frequency + "Hz") - .toString(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/GeoLocation.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/GeoLocation.java deleted file mode 100644 index 7e546531..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/GeoLocation.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.base.MoreObjects; - -/** - * Geo location specified in terms of longitude and latitude. - */ -public class GeoLocation { - - public static final double EARTH_RADIUS_KM = 6378.1370D; - - private final double latitude; - private final double longitude; - - /** - * Creates a new location using the specified coordinates. - * - * @param latitude latitude line - * @param longitude longitude line - */ - public GeoLocation(double latitude, double longitude) { - this.latitude = latitude; - this.longitude = longitude; - } - - /** - * Returns the latitude of this location. - * - * @return latitude - */ - public double latitude() { - return latitude; - } - - /** - * Returns the longitude of this location. - * - * @return longitude - */ - public double longitude() { - return longitude; - } - - /** - * Returns the distance in kilometers, between this location and another. - * - * @param other other geo location - * @return distance in kilometers - */ - public double kilometersTo(GeoLocation other) { - double hereLat = Math.toRadians(latitude); - double hereLon = Math.toRadians(longitude); - double thereLat = Math.toRadians(other.latitude); - double thereLon = Math.toRadians(other.longitude); - - double cos = Math.sin(hereLat) * Math.sin(thereLat) + - Math.cos(hereLat) * Math.cos(thereLat) * Math.cos(hereLon - thereLon); - return Math.acos(cos) * EARTH_RADIUS_KM; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("latitude", latitude) - .add("longitude", longitude) - .toString(); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/GroupedThreadFactory.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/GroupedThreadFactory.java deleted file mode 100644 index 9001cf5f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/GroupedThreadFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.apache.commons.lang3.concurrent.ConcurrentUtils; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ThreadFactory; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Thread factory for creating threads that belong to the specified thread group. - */ -public final class GroupedThreadFactory implements ThreadFactory { - - public static final String DELIMITER = "/"; - - private final ThreadGroup group; - - // Cache of created thread factories. - private static final ConcurrentHashMap<String, GroupedThreadFactory> FACTORIES = - new ConcurrentHashMap<>(); - - /** - * Returns thread factory for producing threads associated with the specified - * group name. The group name-space is hierarchical, based on slash-delimited - * name segments, e.g. {@code onos/intent}. - * - * @param groupName group name - * @return thread factory - */ - public static GroupedThreadFactory groupedThreadFactory(String groupName) { - GroupedThreadFactory factory = FACTORIES.get(groupName); - if (factory != null) { - return factory; - } - - // Find the parent group or root the group hierarchy under default group. - int i = groupName.lastIndexOf(DELIMITER); - if (i > 0) { - String name = groupName.substring(0, i); - ThreadGroup parentGroup = groupedThreadFactory(name).threadGroup(); - factory = new GroupedThreadFactory(new ThreadGroup(parentGroup, groupName)); - } else { - factory = new GroupedThreadFactory(new ThreadGroup(groupName)); - } - - return ConcurrentUtils.putIfAbsent(FACTORIES, groupName, factory); - } - - // Creates a new thread group - private GroupedThreadFactory(ThreadGroup group) { - this.group = group; - } - - /** - * Returns the thread group associated with the factory. - * - * @return thread group - */ - public ThreadGroup threadGroup() { - return group; - } - - @Override - public Thread newThread(Runnable r) { - return new Thread(group, r); - } - - @Override - public String toString() { - return toStringHelper(this).add("group", group).toString(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexDump.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexDump.java deleted file mode 100755 index cfb79390..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexDump.java +++ /dev/null @@ -1,57 +0,0 @@ -/*
- * Copyright 2015 Open Networking Laboratory
- *
- * 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.onlab.util;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * HexDump class an utility to dump buffer in hex format.
- */
-public final class HexDump {
- protected static final Logger log = LoggerFactory.getLogger(HexDump.class);
-
- private HexDump() {
- }
-
- /**
- * Dump the buffer content in hex format.
- *
- * @param buff buffer content to dump in hex format
- */
- public static void dump(ChannelBuffer buff) {
- try {
- byte[] yTemp;
- yTemp = buff.array();
-
- int iStartIndex = buff.readerIndex();
- int iEndIndex = buff.writerIndex();
- do {
- StringBuilder sb = new StringBuilder();
- for (int k = 0; (k < 16) && (iStartIndex < iEndIndex); ++k) {
- if (0 == k % 4) {
- sb.append(String.format(" ")); // blank after 4 bytes
- }
- sb.append(String.format("%02X ", yTemp[iStartIndex++]));
- }
- log.debug(sb.toString());
- } while (iStartIndex < iEndIndex);
- } catch (Exception e) {
- log.error("[HexDump] Invalid buffer: " + e.toString());
- }
- }
-}
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexString.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexString.java deleted file mode 100644 index 962e1119..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/HexString.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.util; - -public final class HexString { - - private HexString() { - } - - /** - * Convert a byte array to a colon-separated hex string. - * - * @param bytes byte array to be converted - * @return converted colon-separated hex string, e.g. "0f:ca:fe:de:ad:be:ef", - * or "(null)" if given byte array is null - */ - public static String toHexString(final byte[] bytes) { - return toHexString(bytes, ":"); - } - - /** - * Convert a byte array to a hex string separated by given separator. - * - * @param bytes byte array to be converted - * @param separator the string use to separate each byte - * @return converted hex string, or "(null)" if given byte array is null - */ - public static String toHexString(final byte[] bytes, String separator) { - if (bytes == null) { - return "(null)"; - } - if (separator == null) { - separator = ""; - } - int i; - StringBuilder ret = new StringBuilder(bytes.length * 3 - 1); - String tmp; - for (i = 0; i < bytes.length; i++) { - if (i > 0) { - ret.append(separator); - } - tmp = Integer.toHexString((bytes[i] & 0xff)); - if (tmp.length() == 1) { - ret.append('0'); - } - ret.append(tmp); - } - return ret.toString(); - } - - /** - * Convert a long number to colon-separated hex string. - * Prepend zero padding until given length. - * - * @param val long number to be converted - * @param padTo prepend zeros until this length - * @return converted colon-separated hex string, e.g. "0f:ca:fe:de:ad:be:ef" - */ - public static String toHexString(final long val, final int padTo) { - char[] arr = Long.toHexString(val).toCharArray(); - StringBuilder ret = new StringBuilder(padTo * 3 - 1); - // prepend the right number of leading zeros - int i = 0; - for (; i < (padTo * 2 - arr.length); i++) { - ret.append('0'); - if ((i % 2) != 0) { - ret.append(':'); - } - } - for (int j = 0; j < arr.length; j++) { - ret.append(arr[j]); - if ((((i + j) % 2) != 0) && (j < (arr.length - 1))) { - ret.append(':'); - } - } - return ret.toString(); - } - - /** - * Convert a long number to colon-separated hex string. - * Prepend zero padding until 8 bytes. - * - * @param val long number to be converted - * @return converted colon-separated hex string, e.g. "0f:ca:fe:de:ad:be:ef" - */ - public static String toHexString(final long val) { - return toHexString(val, 8); - } - - /** - * Convert a colon-separated hex string to byte array. - * - * @param values colon-separated hex string to be converted, - * e.g. "0f:ca:fe:de:ad:be:ef" - * @return converted byte array - * @throws NumberFormatException if input hex string cannot be parsed - */ - public static byte[] fromHexString(final String values) { - String[] octets = values.split(":"); - byte[] ret = new byte[octets.length]; - - for (int i = 0; i < octets.length; i++) { - if (octets[i].length() > 2) { - throw new NumberFormatException("Invalid octet length"); - } - ret[i] = Integer.valueOf(octets[i], 16).byteValue(); - } - return ret; - } - - /** - * Convert a colon-separated hex string to long. - * - * @param value colon-separated hex string to be converted, - * e.g. "00:0f:ca:fe:de:ad:be:ef" - * @return converted long number - * @throws NumberFormatException if input hex string cannot be parsed - */ - public static long toLong(String value) { - String[] octets = value.split(":"); - if (octets.length > 8) { - throw new NumberFormatException("Input string is too big to fit in long: " + value); - } - long l = 0; - for (String octet: octets) { - if (octet.length() > 2) { - throw new NumberFormatException( - "Each colon-separated byte component must consist of 1 or 2 hex digits: " + value); - } - short s = Short.parseShort(octet, 16); - l = (l << 8) + s; - } - return l; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/ItemNotFoundException.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/ItemNotFoundException.java deleted file mode 100644 index 01440abf..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/ItemNotFoundException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.util; - -/** - * Represents condition where an item is not found or not available. - */ -public class ItemNotFoundException extends RuntimeException { - - /** - * Creates a new exception with no message. - */ - public ItemNotFoundException() { - } - - /** - * Creates a new exception with the supplied message. - * @param message error message - */ - public ItemNotFoundException(String message) { - super(message); - } - - /** - * Creates a new exception with the supplied message and cause. - * @param message error message - * @param cause cause of the error - */ - public ItemNotFoundException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/KryoNamespace.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/KryoNamespace.java deleted file mode 100644 index 9977e35d..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/KryoNamespace.java +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.util; - -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang3.tuple.Pair; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.Serializer; -import com.esotericsoftware.kryo.io.ByteBufferInput; -import com.esotericsoftware.kryo.io.ByteBufferOutput; -import com.esotericsoftware.kryo.io.Input; -import com.esotericsoftware.kryo.pool.KryoCallback; -import com.esotericsoftware.kryo.pool.KryoFactory; -import com.esotericsoftware.kryo.pool.KryoPool; -import com.google.common.base.MoreObjects; -import com.google.common.collect.ImmutableList; - -/** - * Pool of Kryo instances, with classes pre-registered. - */ -//@ThreadSafe -public final class KryoNamespace implements KryoFactory, KryoPool { - - /** - * Default buffer size used for serialization. - * - * @see #serialize(Object) - */ - public static final int DEFAULT_BUFFER_SIZE = 4096; - public static final int MAX_BUFFER_SIZE = 100 * 1000 * 1000; - - /** - * ID to use if this KryoNamespace does not define registration id. - */ - public static final int FLOATING_ID = -1; - - /** - * Smallest ID free to use for user defined registrations. - */ - public static final int INITIAL_ID = 11; - - - private final KryoPool pool = new KryoPool.Builder(this) - .softReferences() - .build(); - - private final ImmutableList<RegistrationBlock> registeredBlocks; - - private final boolean registrationRequired; - - - /** - * KryoNamespace builder. - */ - //@NotThreadSafe - public static final class Builder { - - private int blockHeadId = INITIAL_ID; - private List<Pair<Class<?>, Serializer<?>>> types = new ArrayList<>(); - private List<RegistrationBlock> blocks = new ArrayList<>(); - private boolean registrationRequired = true; - - /** - * Builds a {@link KryoNamespace} instance. - * - * @return KryoNamespace - */ - public KryoNamespace build() { - if (!types.isEmpty()) { - blocks.add(new RegistrationBlock(this.blockHeadId, types)); - } - return new KryoNamespace(blocks, registrationRequired).populate(1); - } - - /** - * Sets the next Kryo registration Id for following register entries. - * - * @param id Kryo registration Id - * @return this - * - * @see Kryo#register(Class, Serializer, int) - */ - public Builder nextId(final int id) { - if (!types.isEmpty()) { - blocks.add(new RegistrationBlock(this.blockHeadId, types)); - types = new ArrayList<>(); - } - this.blockHeadId = id; - return this; - } - - /** - * Registers classes to be serialized using Kryo default serializer. - * - * @param expectedTypes list of classes - * @return this - */ - public Builder register(final Class<?>... expectedTypes) { - for (Class<?> clazz : expectedTypes) { - types.add(Pair.of(clazz, null)); - } - return this; - } - - /** - * Registers a class and it's serializer. - * - * @param classes list of classes to register - * @param serializer serializer to use for the class - * @return this - */ - public Builder register(Serializer<?> serializer, final Class<?>... classes) { - for (Class<?> clazz : classes) { - types.add(Pair.of(clazz, serializer)); - } - return this; - } - - private Builder register(RegistrationBlock block) { - if (block.begin() != FLOATING_ID) { - // flush pending types - nextId(block.begin()); - blocks.add(block); - nextId(block.begin() + block.types().size()); - } else { - // flush pending types - final int addedBlockBegin = blockHeadId + types.size(); - nextId(addedBlockBegin); - blocks.add(new RegistrationBlock(addedBlockBegin, block.types())); - nextId(addedBlockBegin + block.types().size()); - } - return this; - } - - /** - * Registers all the class registered to given KryoNamespace. - * - * @param ns KryoNamespace - * @return this - */ - public Builder register(final KryoNamespace ns) { - for (RegistrationBlock block : ns.registeredBlocks) { - this.register(block); - } - return this; - } - - /** - * Sets the registrationRequired flag. - * - * @param registrationRequired Kryo's registrationRequired flag - * @return this - * - * @see Kryo#setRegistrationRequired(boolean) - */ - public Builder setRegistrationRequired(boolean registrationRequired) { - this.registrationRequired = registrationRequired; - return this; - } - } - - /** - * Creates a new {@link KryoNamespace} builder. - * - * @return builder - */ - public static Builder newBuilder() { - return new Builder(); - } - - /** - * Creates a Kryo instance pool. - * - * @param registeredTypes types to register - * @param registrationRequired - */ - private KryoNamespace(final List<RegistrationBlock> registeredTypes, boolean registrationRequired) { - this.registeredBlocks = ImmutableList.copyOf(registeredTypes); - this.registrationRequired = registrationRequired; - } - - /** - * Populates the Kryo pool. - * - * @param instances to add to the pool - * @return this - */ - public KryoNamespace populate(int instances) { - - for (int i = 0; i < instances; ++i) { - release(create()); - } - return this; - } - - /** - * Serializes given object to byte array using Kryo instance in pool. - * <p> - * Note: Serialized bytes must be smaller than {@link #MAX_BUFFER_SIZE}. - * - * @param obj Object to serialize - * @return serialized bytes - */ - public byte[] serialize(final Object obj) { - return serialize(obj, DEFAULT_BUFFER_SIZE); - } - - /** - * Serializes given object to byte array using Kryo instance in pool. - * - * @param obj Object to serialize - * @param bufferSize maximum size of serialized bytes - * @return serialized bytes - */ - public byte[] serialize(final Object obj, final int bufferSize) { - ByteBufferOutput out = new ByteBufferOutput(bufferSize, MAX_BUFFER_SIZE); - try { - Kryo kryo = borrow(); - try { - kryo.writeClassAndObject(out, obj); - out.flush(); - return out.toBytes(); - } finally { - release(kryo); - } - } finally { - out.release(); - } - } - - /** - * Serializes given object to byte buffer using Kryo instance in pool. - * - * @param obj Object to serialize - * @param buffer to write to - */ - public void serialize(final Object obj, final ByteBuffer buffer) { - ByteBufferOutput out = new ByteBufferOutput(buffer); - Kryo kryo = borrow(); - try { - kryo.writeClassAndObject(out, obj); - out.flush(); - } finally { - release(kryo); - } - } - - /** - * Serializes given object to OutputStream using Kryo instance in pool. - * - * @param obj Object to serialize - * @param stream to write to - */ - public void serialize(final Object obj, final OutputStream stream) { - serialize(obj, stream, DEFAULT_BUFFER_SIZE); - } - - /** - * Serializes given object to OutputStream using Kryo instance in pool. - * - * @param obj Object to serialize - * @param stream to write to - * @param bufferSize size of the buffer in front of the stream - */ - public void serialize(final Object obj, final OutputStream stream, final int bufferSize) { - ByteBufferOutput out = new ByteBufferOutput(stream, bufferSize); - Kryo kryo = borrow(); - try { - kryo.writeClassAndObject(out, obj); - out.flush(); - } finally { - release(kryo); - } - } - - /** - * Deserializes given byte array to Object using Kryo instance in pool. - * - * @param bytes serialized bytes - * @param <T> deserialized Object type - * @return deserialized Object - */ - public <T> T deserialize(final byte[] bytes) { - Input in = new Input(bytes); - Kryo kryo = borrow(); - try { - @SuppressWarnings("unchecked") - T obj = (T) kryo.readClassAndObject(in); - return obj; - } finally { - release(kryo); - } - } - - /** - * Deserializes given byte buffer to Object using Kryo instance in pool. - * - * @param buffer input with serialized bytes - * @param <T> deserialized Object type - * @return deserialized Object - */ - public <T> T deserialize(final ByteBuffer buffer) { - ByteBufferInput in = new ByteBufferInput(buffer); - Kryo kryo = borrow(); - try { - @SuppressWarnings("unchecked") - T obj = (T) kryo.readClassAndObject(in); - return obj; - } finally { - release(kryo); - } - } - - /** - * Deserializes given InputStream to an Object using Kryo instance in pool. - * - * @param stream input stream - * @param <T> deserialized Object type - * @return deserialized Object - */ - public <T> T deserialize(final InputStream stream) { - return deserialize(stream, DEFAULT_BUFFER_SIZE); - } - - /** - * Deserializes given InputStream to an Object using Kryo instance in pool. - * - * @param stream input stream - * @param <T> deserialized Object type - * @return deserialized Object - * @param bufferSize size of the buffer in front of the stream - */ - public <T> T deserialize(final InputStream stream, final int bufferSize) { - ByteBufferInput in = new ByteBufferInput(stream, bufferSize); - Kryo kryo = borrow(); - try { - @SuppressWarnings("unchecked") - T obj = (T) kryo.readClassAndObject(in); - return obj; - } finally { - release(kryo); - } - } - - /** - * Creates a Kryo instance. - * - * @return Kryo instance - */ - @Override - public Kryo create() { - Kryo kryo = new Kryo(); - kryo.setRegistrationRequired(registrationRequired); - for (RegistrationBlock block : registeredBlocks) { - int id = block.begin(); - if (id == FLOATING_ID) { - id = kryo.getNextRegistrationId(); - } - for (Pair<Class<?>, Serializer<?>> entry : block.types()) { - final Serializer<?> serializer = entry.getRight(); - if (serializer == null) { - kryo.register(entry.getLeft(), id++); - } else { - kryo.register(entry.getLeft(), serializer, id++); - } - } - } - return kryo; - } - - @Override - public Kryo borrow() { - return pool.borrow(); - } - - @Override - public void release(Kryo kryo) { - pool.release(kryo); - } - - @Override - public <T> T run(KryoCallback<T> callback) { - return pool.run(callback); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(getClass()) - .add("registeredBlocks", registeredBlocks) - .toString(); - } - - static final class RegistrationBlock { - private final int begin; - private final ImmutableList<Pair<Class<?>, Serializer<?>>> types; - - public RegistrationBlock(int begin, List<Pair<Class<?>, Serializer<?>>> types) { - this.begin = begin; - this.types = ImmutableList.copyOf(types); - } - - public int begin() { - return begin; - } - - public ImmutableList<Pair<Class<?>, Serializer<?>>> types() { - return types; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(getClass()) - .add("begin", begin) - .add("types", types) - .toString(); - } - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/NewConcurrentHashMap.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/NewConcurrentHashMap.java deleted file mode 100644 index 2d222eac..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/NewConcurrentHashMap.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.commons.lang3.concurrent.ConcurrentInitializer; - -/** - * Creates an instance of new ConcurrentHashMap on each {@link #get()} call. - * <p> - * To be used with - * {@link org.apache.commons.lang3.concurrent.ConcurrentUtils#createIfAbsent} - * </p> - * - * @param <K> ConcurrentHashMap key type - * @param <V> ConcurrentHashMap value type - */ -public final class NewConcurrentHashMap<K, V> - implements ConcurrentInitializer<ConcurrentMap<K, V>> { - - public static final NewConcurrentHashMap<?, ?> INSTANCE = new NewConcurrentHashMap<>(); - - @SuppressWarnings("unchecked") - public static <K, V> NewConcurrentHashMap<K, V> ifNeeded() { - return (NewConcurrentHashMap<K, V>) INSTANCE; - } - - @Override - public ConcurrentMap<K, V> get() { - return new ConcurrentHashMap<>(); - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/PositionalParameterStringFormatter.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/PositionalParameterStringFormatter.java deleted file mode 100644 index 647e0c0d..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/PositionalParameterStringFormatter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -/** - * Allows slf4j style formatting of parameters into a string. - */ -public final class PositionalParameterStringFormatter { - - /** - * Hide default constructor. - */ - private PositionalParameterStringFormatter() { - } - - /** - * Formats a string using slf4j style positional parameter replacement. - * Instances of "{}" in the source string are replaced in order by the - * specified parameter values as strings. - * - * @param source original string to format - * @param parameters list of parameters that will be substituted - * @return formatted string - */ - public static String format(String source, Object... parameters) { - String current = source; - for (Object parameter : parameters) { - if (!current.contains("{}")) { - return current; - } - current = current.replaceFirst("\\{\\}", String.valueOf(parameter)); - } - return current; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/RetryingFunction.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/RetryingFunction.java deleted file mode 100644 index 484e236f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/RetryingFunction.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.function.Function; - -import com.google.common.base.Throwables; - -/** - * Function that retries execution on failure. - * - * @param <U> input type - * @param <V> output type - */ -public class RetryingFunction<U, V> implements Function<U, V> { - - private final Function<U, V> baseFunction; - private final Class<? extends Throwable> exceptionClass; - private final int maxRetries; - private final int maxDelayBetweenRetries; - - public RetryingFunction(Function<U, V> baseFunction, - Class<? extends Throwable> exceptionClass, - int maxRetries, - int maxDelayBetweenRetries) { - this.baseFunction = baseFunction; - this.exceptionClass = exceptionClass; - this.maxRetries = maxRetries; - this.maxDelayBetweenRetries = maxDelayBetweenRetries; - } - - @Override - public V apply(U input) { - int retryAttempts = 0; - while (true) { - try { - return baseFunction.apply(input); - } catch (Throwable t) { - if (!exceptionClass.isAssignableFrom(t.getClass()) || retryAttempts == maxRetries) { - Throwables.propagate(t); - } - Tools.randomDelay(maxDelayBetweenRetries); - retryAttempts++; - } - } - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/RichComparable.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/RichComparable.java deleted file mode 100644 index 8a49bba9..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/RichComparable.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Extends useful methods for comparison to {@link Comparable} interface. - * - * @param <T> type of instance to be compared - */ -public interface RichComparable<T> extends Comparable<T> { - /** - * Compares if this object is less than the specified object. - * - * @param other the object to be compared - * @return true if this object is less than the specified object - */ - default boolean isLessThan(T other) { - return compareTo(checkNotNull(other)) < 0; - } - - /** - * Compares if this object is greater than the specified object. - * - * @param other the object to be compared - * @return true if this object is less thant the specified object - */ - default boolean isGreaterThan(T other) { - return compareTo(checkNotNull(other)) > 0; - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SharedExecutorService.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SharedExecutorService.java deleted file mode 100644 index 051155ce..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SharedExecutorService.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * Executor service wrapper for shared executors with safeguards on shutdown - * to prevent inadvertent shutdown. - */ -class SharedExecutorService implements ExecutorService { - - private static final String NOT_ALLOWED = "Shutdown of shared executor is not allowed"; - - private ExecutorService executor; - - /** - * Creates a wrapper for the given executor service. - * - * @param executor executor service to wrap - */ - SharedExecutorService(ExecutorService executor) { - this.executor = executor; - } - - /** - * Returns the backing executor service. - * - * @return backing executor service - */ - ExecutorService backingExecutor() { - return executor; - } - - /** - * Swaps the backing executor with a new one and shuts down the old one. - * - * @param executor new executor service - */ - void setBackingExecutor(ExecutorService executor) { - ExecutorService oldExecutor = this.executor; - this.executor = executor; - oldExecutor.shutdown(); - } - - @Override - public void shutdown() { - throw new UnsupportedOperationException(NOT_ALLOWED); - } - - @Override - public List<Runnable> shutdownNow() { - throw new UnsupportedOperationException(NOT_ALLOWED); - } - - @Override - public boolean isShutdown() { - return executor.isShutdown(); - } - - @Override - public boolean isTerminated() { - return executor.isTerminated(); - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit unit) - throws InterruptedException { - return executor.awaitTermination(timeout, unit); - } - - @Override - public <T> Future<T> submit(Callable<T> task) { - return executor.submit(task); - } - - @Override - public <T> Future<T> submit(Runnable task, T result) { - return executor.submit(task, result); - } - - @Override - public Future<?> submit(Runnable task) { - return executor.submit(task); - } - - @Override - public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) - throws InterruptedException { - return executor.invokeAll(tasks); - } - - @Override - public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, - long timeout, TimeUnit unit) - throws InterruptedException { - return executor.invokeAll(tasks, timeout, unit); - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> tasks) - throws InterruptedException, ExecutionException { - return executor.invokeAny(tasks); - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> tasks, - long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - return executor.invokeAny(tasks, timeout, unit); - } - - @Override - public void execute(Runnable command) { - executor.execute(command); - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SharedExecutors.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SharedExecutors.java deleted file mode 100644 index 0dadce85..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SharedExecutors.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.Timer; -import java.util.concurrent.ExecutorService; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.concurrent.Executors.newFixedThreadPool; -import static java.util.concurrent.Executors.newSingleThreadExecutor; -import static org.onlab.util.Tools.groupedThreads; - -/** - * Utility for managing a set of shared execution resources, such as a timer, - * single thread executor and thread pool executor for use by various parts of - * the platform or by applications. - * <p> - * Whenever possible, use of these shared resources is encouraged over creating - * separate ones. - * </p> - */ -public final class SharedExecutors { - - public static final int DEFAULT_POOL_SIZE = 30; - - private static SharedExecutorService singleThreadExecutor = - new SharedExecutorService( - newSingleThreadExecutor(groupedThreads("onos/shared", - "onos-single-executor"))); - - private static SharedExecutorService poolThreadExecutor = - new SharedExecutorService( - newFixedThreadPool(DEFAULT_POOL_SIZE, - groupedThreads("onos/shared", - "onos-pool-executor-%d"))); - - private static SharedTimer sharedTimer = new SharedTimer(); - - // Ban public construction - private SharedExecutors() { - } - - /** - * Returns the shared single thread executor. - * - * @return shared single thread executor - */ - public static ExecutorService getSingleThreadExecutor() { - return singleThreadExecutor; - } - - /** - * Returns the shared thread pool executor. - * - * @return shared executor pool - */ - public static ExecutorService getPoolThreadExecutor() { - return poolThreadExecutor; - } - - /** - * Returns the shared timer. - * - * @return shared timer - */ - public static Timer getTimer() { - return sharedTimer; - } - - /** - * Sets the shared thread pool size. - * - * @param poolSize new pool size - */ - public static void setPoolSize(int poolSize) { - checkArgument(poolSize > 0, "Shared pool size size must be greater than 0"); - poolThreadExecutor.setBackingExecutor( - newFixedThreadPool(poolSize, groupedThreads("onos/shared", - "onos-pool-executor-%d"))); - } - - /** - * Shuts down all shared timers and executors and therefore should be - * called only by the framework. - */ - public static void shutdown() { - sharedTimer.shutdown(); - singleThreadExecutor.backingExecutor().shutdown(); - poolThreadExecutor.backingExecutor().shutdown(); - } - - // Timer extension which does not allow outside cancel method. - private static class SharedTimer extends Timer { - - public SharedTimer() { - super("onos-shared-timer"); - } - - @Override - public void cancel() { - throw new UnsupportedOperationException("Cancel of shared timer is not allowed"); - } - - private void shutdown() { - super.cancel(); - } - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SlidingWindowCounter.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SlidingWindowCounter.java deleted file mode 100644 index 4f0093c0..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/SlidingWindowCounter.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkArgument; - -/** - * Maintains a sliding window of value counts. The sliding window counter is - * initialized with a number of window slots. Calls to #incrementCount() will - * increment the value in the current window slot. Periodically the window - * slides and the oldest value count is dropped. Calls to #get() will get the - * total count for the last N window slots. - */ -public final class SlidingWindowCounter { - - private volatile int headSlot; - private final int windowSlots; - - private final List<AtomicLong> counters; - - private final ScheduledExecutorService background; - - private static final int SLIDE_WINDOW_PERIOD_SECONDS = 1; - - /** - * Creates a new sliding window counter with the given total number of - * window slots. - * - * @param windowSlots total number of window slots - */ - public SlidingWindowCounter(int windowSlots) { - checkArgument(windowSlots > 0, "Window size must be a positive integer"); - - this.windowSlots = windowSlots; - this.headSlot = 0; - - // Initialize each item in the list to an AtomicLong of 0 - this.counters = Collections.nCopies(windowSlots, 0) - .stream() - .map(AtomicLong::new) - .collect(Collectors.toCollection(ArrayList::new)); - - background = Executors.newSingleThreadScheduledExecutor(); - background.scheduleWithFixedDelay(this::advanceHead, 0, - SLIDE_WINDOW_PERIOD_SECONDS, TimeUnit.SECONDS); - } - - /** - * Releases resources used by the SlidingWindowCounter. - */ - public void destroy() { - background.shutdownNow(); - } - - /** - * Increments the count of the current window slot by 1. - */ - public void incrementCount() { - incrementCount(headSlot, 1); - } - - /** - * Increments the count of the current window slot by the given value. - * - * @param value value to increment by - */ - public void incrementCount(long value) { - incrementCount(headSlot, value); - } - - private void incrementCount(int slot, long value) { - counters.get(slot).addAndGet(value); - } - - /** - * Gets the total count for the last N window slots. - * - * @param slots number of slots to include in the count - * @return total count for last N slots - */ - public long get(int slots) { - checkArgument(slots <= windowSlots, - "Requested window must be less than the total window slots"); - - long sum = 0; - - for (int i = 0; i < slots; i++) { - int currentIndex = headSlot - i; - if (currentIndex < 0) { - currentIndex = counters.size() + currentIndex; - } - sum += counters.get(currentIndex).get(); - } - - return sum; - } - - void advanceHead() { - counters.get(slotAfter(headSlot)).set(0); - headSlot = slotAfter(headSlot); - } - - private int slotAfter(int slot) { - return (slot + 1) % windowSlots; - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Spectrum.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Spectrum.java deleted file mode 100644 index ca01c6e3..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Spectrum.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -/** - * Telecom optical wavelength bands: O, E, S, C, L and U bands. - * - * See ITU-T G-Series Recommendations, Supplement 39 - * See ITU-T G.694.1 for center frequency definition. - */ -public final class Spectrum { - - // Center frequency - public static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1); - - // O band (original): 1260 to 1360 nm - public static final Frequency O_BAND_MIN = Frequency.ofTHz(220.436); - public static final Frequency O_BAND_MAX = Frequency.ofTHz(237.931); - - // E band (extended): 1360 to 1460 nm - public static final Frequency E_BAND_MIN = Frequency.ofTHz(205.337); - public static final Frequency E_BAND_MAX = Frequency.ofTHz(220.436); - - // S band (short wavelength): 1460 to 1530 nm - public static final Frequency S_BAND_MIN = Frequency.ofTHz(195.943); - public static final Frequency S_BAND_MAX = Frequency.ofTHz(205.337); - - // C band (conventional): 1530 to 1565 nm - public static final Frequency C_BAND_MIN = Frequency.ofTHz(191.561); - public static final Frequency C_BAND_MAX = Frequency.ofTHz(195.943); - - // L band (long wavelength): 1565 to 1625 nm - public static final Frequency L_BAND_MIN = Frequency.ofTHz(184.488); - public static final Frequency L_BAND_MAX = Frequency.ofTHz(191.561); - - // U band (ultra-long wavelength): 1625 to 1675 nm - public static final Frequency U_BAND_MIN = Frequency.ofTHz(178.981); - public static final Frequency U_BAND_MAX = Frequency.ofTHz(184.488); - - private Spectrum() { - } -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Timer.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Timer.java deleted file mode 100644 index fe508839..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Timer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.util; - -import org.jboss.netty.util.HashedWheelTimer; - -/** - * Hashed-wheel timer singleton. Care must be taken to shutdown the timer - * only when the VM is ready to exit. - */ -public final class Timer { - - private static volatile HashedWheelTimer timer; - - // Ban public construction - private Timer() { - } - - /** - * Returns the singleton hashed-wheel timer. - * - * @return hashed-wheel timer - */ - public static HashedWheelTimer getTimer() { - if (Timer.timer == null) { - initTimer(); - } - return Timer.timer; - } - - private static synchronized void initTimer() { - if (Timer.timer == null) { - HashedWheelTimer hwTimer = new HashedWheelTimer(); - hwTimer.start(); - Timer.timer = hwTimer; - } - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Tools.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Tools.java deleted file mode 100644 index ffefbfd4..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/Tools.java +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.util; - -import static java.nio.file.Files.delete; -import static java.nio.file.Files.walkFileTree; -import static org.onlab.util.GroupedThreadFactory.groupedThreadFactory; -import static org.slf4j.LoggerFactory.getLogger; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Dictionary; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import org.slf4j.Logger; - -import com.google.common.base.Strings; -import com.google.common.primitives.UnsignedLongs; -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -/** - * Miscellaneous utility methods. - */ -public abstract class Tools { - - private Tools() { - } - - private static final Logger log = getLogger(Tools.class); - - private static Random random = new Random(); - - /** - * Returns a thread factory that produces threads named according to the - * supplied name pattern. - * - * @param pattern name pattern - * @return thread factory - */ - public static ThreadFactory namedThreads(String pattern) { - return new ThreadFactoryBuilder() - .setNameFormat(pattern) - .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e)) - .build(); - } - - /** - * Returns a thread factory that produces threads named according to the - * supplied name pattern and from the specified thread-group. The thread - * group name is expected to be specified in slash-delimited format, e.g. - * {@code onos/intent}. The thread names will be produced by converting - * the thread group name into dash-delimited format and pre-pended to the - * specified pattern. - * - * @param groupName group name in slash-delimited format to indicate hierarchy - * @param pattern name pattern - * @return thread factory - */ - public static ThreadFactory groupedThreads(String groupName, String pattern) { - return new ThreadFactoryBuilder() - .setThreadFactory(groupedThreadFactory(groupName)) - .setNameFormat(groupName.replace(GroupedThreadFactory.DELIMITER, "-") + "-" + pattern) - .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e)) - .build(); - } - - /** - * Returns a thread factory that produces threads with MIN_PRIORITY. - * - * @param factory backing ThreadFactory - * @return thread factory - */ - public static ThreadFactory minPriority(ThreadFactory factory) { - return new ThreadFactoryBuilder() - .setThreadFactory(factory) - .setPriority(Thread.MIN_PRIORITY) - .build(); - } - - /** - * Returns true if the collection is null or is empty. - * - * @param collection collection to test - * @return true if null or empty; false otherwise - */ - public static boolean isNullOrEmpty(Collection collection) { - return collection == null || collection.isEmpty(); - } - - /** - * Returns the specified item if that item is not null; otherwise throws - * not found exception. - * - * @param item item to check - * @param message not found message - * @param <T> item type - * @return item if not null - * @throws org.onlab.util.ItemNotFoundException if item is null - */ - public static <T> T nullIsNotFound(T item, String message) { - if (item == null) { - throw new ItemNotFoundException(message); - } - return item; - } - - /** - * Returns the specified set if the set is not null and not empty; - * otherwise throws a not found exception. - * - * @param item set to check - * @param message not found message - * @param <T> Set item type - * @return item if not null and not empty - * @throws org.onlab.util.ItemNotFoundException if set is null or empty - */ - public static <T> Set<T> emptyIsNotFound(Set<T> item, String message) { - if (item == null || item.isEmpty()) { - throw new ItemNotFoundException(message); - } - return item; - } - - /** - * Returns the specified item if that item is not null; otherwise throws - * bad argument exception. - * - * @param item item to check - * @param message not found message - * @param <T> item type - * @return item if not null - * @throws IllegalArgumentException if item is null - */ - public static <T> T nullIsIllegal(T item, String message) { - if (item == null) { - throw new IllegalArgumentException(message); - } - return item; - } - - /** - * Converts a string from hex to long. - * - * @param string hex number in string form; sans 0x - * @return long value - */ - public static long fromHex(String string) { - return UnsignedLongs.parseUnsignedLong(string, 16); - } - - /** - * Converts a long value to hex string; 16 wide and sans 0x. - * - * @param value long value - * @return hex string - */ - public static String toHex(long value) { - return Strings.padStart(UnsignedLongs.toString(value, 16), 16, '0'); - } - - /** - * Converts a long value to hex string; 16 wide and sans 0x. - * - * @param value long value - * @param width string width; zero padded - * @return hex string - */ - public static String toHex(long value, int width) { - return Strings.padStart(UnsignedLongs.toString(value, 16), width, '0'); - } - - /** - * Returns a copy of the input byte array. - * - * @param original input - * @return copy of original - */ - public static byte[] copyOf(byte[] original) { - return Arrays.copyOf(original, original.length); - } - - /** - * Get property as a string value. - * - * @param properties properties to be looked up - * @param propertyName the name of the property to look up - * @return value when the propertyName is defined or return null - */ - public static String get(Dictionary<?, ?> properties, String propertyName) { - Object v = properties.get(propertyName); - String s = (v instanceof String) ? (String) v : - v != null ? v.toString() : null; - return Strings.isNullOrEmpty(s) ? null : s.trim(); - } - - /** - * Suspends the current thread for a specified number of millis. - * - * @param ms number of millis - */ - public static void delay(int ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted", e); - } - } - - /** - * Returns a function that retries execution on failure. - * @param base base function - * @param exceptionClass type of exception for which to retry - * @param maxRetries max number of retries before giving up - * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from - * the interval (0, maxDelayBetweenRetries] - * @return function - * @param <U> type of function input - * @param <V> type of function output - */ - public static <U, V> Function<U, V> retryable(Function<U, V> base, - Class<? extends Throwable> exceptionClass, - int maxRetries, - int maxDelayBetweenRetries) { - return new RetryingFunction<>(base, exceptionClass, maxRetries, maxDelayBetweenRetries); - } - - /** - * Returns a Supplier that retries execution on failure. - * @param base base supplier - * @param exceptionClass type of exception for which to retry - * @param maxRetries max number of retries before giving up - * @param maxDelayBetweenRetries max delay between successive retries. The actual delay is randomly picked from - * the interval (0, maxDelayBetweenRetries] - * @return supplier - * @param <V> type of supplied result - */ - public static <V> Supplier<V> retryable(Supplier<V> base, - Class<? extends Throwable> exceptionClass, - int maxRetries, - int maxDelayBetweenRetries) { - return () -> new RetryingFunction<>(v -> base.get(), - exceptionClass, - maxRetries, - maxDelayBetweenRetries).apply(null); - } - - /** - * Suspends the current thread for a random number of millis between 0 and - * the indicated limit. - * - * @param ms max number of millis - */ - public static void randomDelay(int ms) { - try { - Thread.sleep(random.nextInt(ms)); - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted", e); - } - } - - /** - * Suspends the current thread for a specified number of millis and nanos. - * - * @param ms number of millis - * @param nanos number of nanos - */ - public static void delay(int ms, int nanos) { - try { - Thread.sleep(ms, nanos); - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted", e); - } - } - - /** - * Slurps the contents of a file into a list of strings, one per line. - * - * @param path file path - * @return file contents - * @deprecated in Emu release - */ - @Deprecated - public static List<String> slurp(File path) { - try ( - BufferedReader br = new BufferedReader( - new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8)); - ) { - List<String> lines = new ArrayList<>(); - String line; - while ((line = br.readLine()) != null) { - lines.add(line); - } - return lines; - - } catch (IOException e) { - return null; - } - } - - /** - * Purges the specified directory path. Use with great caution since - * no attempt is made to check for symbolic links, which could result in - * deletion of unintended files. - * - * @param path directory to be removed - * @throws java.io.IOException if unable to remove contents - */ - public static void removeDirectory(String path) throws IOException { - DirectoryDeleter visitor = new DirectoryDeleter(); - File dir = new File(path); - if (dir.exists() && dir.isDirectory()) { - walkFileTree(Paths.get(path), visitor); - if (visitor.exception != null) { - throw visitor.exception; - } - } - } - - /** - * Purges the specified directory path. Use with great caution since - * no attempt is made to check for symbolic links, which could result in - * deletion of unintended files. - * - * @param dir directory to be removed - * @throws java.io.IOException if unable to remove contents - */ - public static void removeDirectory(File dir) throws IOException { - DirectoryDeleter visitor = new DirectoryDeleter(); - if (dir.exists() && dir.isDirectory()) { - walkFileTree(Paths.get(dir.getAbsolutePath()), visitor); - if (visitor.exception != null) { - throw visitor.exception; - } - } - } - - // Auxiliary path visitor for recursive directory structure removal. - private static class DirectoryDeleter extends SimpleFileVisitor<Path> { - - private IOException exception; - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) - throws IOException { - if (attributes.isRegularFile()) { - delete(file); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path directory, IOException ioe) - throws IOException { - delete(directory); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(Path file, IOException ioe) - throws IOException { - this.exception = ioe; - return FileVisitResult.TERMINATE; - } - } - - /** - * Returns a human friendly time ago string for a specified system time. - * - * @param unixTime system time in millis - * @return human friendly time ago - */ - public static String timeAgo(long unixTime) { - long deltaMillis = System.currentTimeMillis() - unixTime; - long secondsSince = (long) (deltaMillis / 1000.0); - long minsSince = (long) (deltaMillis / (1000.0 * 60)); - long hoursSince = (long) (deltaMillis / (1000.0 * 60 * 60)); - long daysSince = (long) (deltaMillis / (1000.0 * 60 * 60 * 24)); - if (daysSince > 0) { - return String.format("%dd ago", daysSince); - } else if (hoursSince > 0) { - return String.format("%dh ago", hoursSince); - } else if (minsSince > 0) { - return String.format("%dm ago", minsSince); - } else if (secondsSince > 0) { - return String.format("%ds ago", secondsSince); - } else { - return "just now"; - } - } - - /** - * Copies the specified directory path. Use with great caution since - * no attempt is made to check for symbolic links, which could result in - * copy of unintended files. - * - * @param src directory to be copied - * @param dst destination directory to be removed - * @throws java.io.IOException if unable to remove contents - */ - public static void copyDirectory(String src, String dst) throws IOException { - walkFileTree(Paths.get(src), new DirectoryCopier(src, dst)); - } - - /** - * Copies the specified directory path. Use with great caution since - * no attempt is made to check for symbolic links, which could result in - * copy of unintended files. - * - * @param src directory to be copied - * @param dst destination directory to be removed - * @throws java.io.IOException if unable to remove contents - */ - public static void copyDirectory(File src, File dst) throws IOException { - walkFileTree(Paths.get(src.getAbsolutePath()), - new DirectoryCopier(src.getAbsolutePath(), - dst.getAbsolutePath())); - } - - /** - * Returns the future value when complete or if future - * completes exceptionally returns the defaultValue. - * - * @param future future - * @param defaultValue default value - * @param <T> future value type - * @return future value when complete or if future - * completes exceptionally returns the defaultValue. - */ - public static <T> T futureGetOrElse(Future<T> future, T defaultValue) { - try { - return future.get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return defaultValue; - } catch (ExecutionException e) { - return defaultValue; - } - } - - /** - * Returns the future value when complete or if future - * completes exceptionally returns the defaultValue. - * - * @param future future - * @param timeout time to wait for successful completion - * @param timeUnit time unit - * @param defaultValue default value - * @param <T> future value type - * @return future value when complete or if future - * completes exceptionally returns the defaultValue. - */ - public static <T> T futureGetOrElse(Future<T> future, - long timeout, - TimeUnit timeUnit, - T defaultValue) { - try { - return future.get(timeout, timeUnit); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return defaultValue; - } catch (ExecutionException | TimeoutException e) { - return defaultValue; - } - } - - /** - * Returns a future that is completed exceptionally. - * - * @param t exception - * @param <T> future value type - * @return future - */ - public static <T> CompletableFuture<T> exceptionalFuture(Throwable t) { - CompletableFuture<T> future = new CompletableFuture<>(); - future.completeExceptionally(t); - return future; - } - - /** - * Returns the contents of {@code ByteBuffer} as byte array. - * <p> - * WARNING: There is a performance cost due to array copy - * when using this method. - * - * @param buffer byte buffer - * @return byte array containing the byte buffer contents - */ - public static byte[] byteBuffertoArray(ByteBuffer buffer) { - int length = buffer.remaining(); - if (buffer.hasArray()) { - int offset = buffer.arrayOffset() + buffer.position(); - return Arrays.copyOfRange(buffer.array(), offset, offset + length); - } - byte[] bytes = new byte[length]; - buffer.duplicate().get(bytes); - return bytes; - } - - /** - * Converts an iterable to a stream. - * - * @param it iterable to convert - * @param <T> type if item - * @return iterable as a stream - */ - public static <T> Stream<T> stream(Iterable<T> it) { - return StreamSupport.stream(it.spliterator(), false); - } - - // Auxiliary path visitor for recursive directory structure copying. - private static class DirectoryCopier extends SimpleFileVisitor<Path> { - private Path src; - private Path dst; - private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING; - - DirectoryCopier(String src, String dst) { - this.src = Paths.get(src); - this.dst = Paths.get(dst); - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - Path targetPath = dst.resolve(src.relativize(dir)); - if (!Files.exists(targetPath)) { - Files.createDirectory(targetPath); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.copy(file, dst.resolve(src.relativize(file)), copyOption); - return FileVisitResult.CONTINUE; - } - } - -} diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/TriConsumer.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/TriConsumer.java deleted file mode 100644 index d1963c46..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/TriConsumer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -/** - * A consumer that accepts three arguments. - * - * @param <U> type of first argument - * @param <V> type of second argument - * @param <W> type of third argument - */ -public interface TriConsumer<U, V, W> { - - /** - * Applies the given arguments to the function. - * @param arg1 first argument - * @param arg2 second argument - * @param arg3 third argument - */ - void accept(U arg1, V arg2, W arg3); - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/package-info.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/util/package-info.java deleted file mode 100644 index 06cc394f..00000000 --- a/framework/src/onos/utils/misc/src/main/java/org/onlab/util/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Miscellaneous domain-agnostic utilities. - */ -package org.onlab.util; diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AbstractEdgeTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AbstractEdgeTest.java deleted file mode 100644 index 6e8635dd..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AbstractEdgeTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -/** - * Test of the base edge implementation. - */ -public class AbstractEdgeTest { - - @Test - public void equality() { - TestVertex v1 = new TestVertex("1"); - TestVertex v2 = new TestVertex("2"); - new EqualsTester() - .addEqualityGroup(new TestEdge(v1, v2, 1), - new TestEdge(v1, v2, 1)) - .addEqualityGroup(new TestEdge(v2, v1, 1)) - .testEquals(); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AbstractGraphPathSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AbstractGraphPathSearchTest.java deleted file mode 100644 index b42cacf6..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AbstractGraphPathSearchTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import org.junit.Test; - -import static com.google.common.collect.ImmutableSet.of; -import static org.junit.Assert.assertEquals; - -/** - * Base for all graph search tests. - */ -public abstract class AbstractGraphPathSearchTest extends GraphTest { - - /** - * Creates a test-specific graph search to exercise. - * - * @return graph search - */ - protected abstract AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch(); - - @Test(expected = IllegalArgumentException.class) - public void noSuchSourceArgument() { - graphSearch().search(new AdjacencyListsGraph<>(of(B, C), - of(new TestEdge(B, C, 1))), - A, H, weight, 1); - } - - @Test(expected = NullPointerException.class) - public void nullGraphArgument() { - graphSearch().search(null, A, H, weight, 1); - } - - @Test(expected = NullPointerException.class) - public void nullSourceArgument() { - graphSearch().search(new AdjacencyListsGraph<>(of(B, C), - of(new TestEdge(B, C, 1))), - null, H, weight, 1); - } - - @Test - public void samenessThreshold() { - AbstractGraphPathSearch<TestVertex, TestEdge> search = graphSearch(); - search.setSamenessThreshold(0.3); - assertEquals("incorrect threshold", 0.3, search.samenessThreshold(), 0.01); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AdjacencyListsGraphTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AdjacencyListsGraphTest.java deleted file mode 100644 index 1f22b5c4..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/AdjacencyListsGraphTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.collect.ImmutableSet; -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import java.util.Set; - -import static org.junit.Assert.assertEquals; - -/** - * Tests of the graph implementation. - */ -public class AdjacencyListsGraphTest { - - private static final TestVertex A = new TestVertex("A"); - private static final TestVertex B = new TestVertex("B"); - private static final TestVertex C = new TestVertex("C"); - private static final TestVertex D = new TestVertex("D"); - private static final TestVertex E = new TestVertex("E"); - private static final TestVertex F = new TestVertex("F"); - private static final TestVertex G = new TestVertex("G"); - - private final Set<TestEdge> edges = - ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(B, C, 1), - new TestEdge(C, D, 1), new TestEdge(D, A, 1), - new TestEdge(B, D, 1)); - - @Test - public void equality() { - Set<TestVertex> vertexes = ImmutableSet.of(A, B, C, D, E, F); - Set<TestVertex> vertexes2 = ImmutableSet.of(A, B, C, D, E, F, G); - - AdjacencyListsGraph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(vertexes, edges); - AdjacencyListsGraph<TestVertex, TestEdge> same = new AdjacencyListsGraph<>(vertexes, edges); - AdjacencyListsGraph<TestVertex, TestEdge> different = new AdjacencyListsGraph<>(vertexes2, edges); - - new EqualsTester() - .addEqualityGroup(graph, same) - .addEqualityGroup(different) - .testEquals(); - } - - @Test - public void basics() { - Set<TestVertex> vertexes = ImmutableSet.of(A, B, C, D, E, F); - AdjacencyListsGraph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(vertexes, edges); - assertEquals("incorrect vertex count", 6, graph.getVertexes().size()); - assertEquals("incorrect edge count", 5, graph.getEdges().size()); - - assertEquals("incorrect egress edge count", 1, graph.getEdgesFrom(A).size()); - assertEquals("incorrect ingress edge count", 1, graph.getEdgesTo(A).size()); - assertEquals("incorrect ingress edge count", 1, graph.getEdgesTo(C).size()); - assertEquals("incorrect egress edge count", 2, graph.getEdgesFrom(B).size()); - assertEquals("incorrect ingress edge count", 2, graph.getEdgesTo(D).size()); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java deleted file mode 100644 index ff363bfb..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/BellmanFordGraphSearchTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import org.junit.Test; - -import java.util.HashSet; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.onlab.graph.GraphPathSearch.ALL_PATHS; - -/** - * Test of the Bellman-Ford algorithm. - */ -public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest { - - @Override - protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { - return new BellmanFordGraphSearch<>(); - } - - @Test - @Override - public void defaultGraphTest() { - executeDefaultTest(7, 5, 5.0); - } - - @Test - public void defaultHopCountWeight() { - weight = null; - executeDefaultTest(10, 3, 3.0); - } - - @Test - public void searchGraphWithNegativeCycles() { - Set<TestVertex> vertexes = new HashSet<>(vertexes()); - vertexes.add(Z); - - Set<TestEdge> edges = new HashSet<>(edges()); - edges.add(new TestEdge(G, Z, 1.0)); - edges.add(new TestEdge(Z, G, -2.0)); - - graph = new AdjacencyListsGraph<>(vertexes, edges); - - GraphPathSearch<TestVertex, TestEdge> search = graphSearch(); - Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, H, weight, ALL_PATHS).paths(); - assertEquals("incorrect paths count", 1, paths.size()); - - Path p = paths.iterator().next(); - assertEquals("incorrect src", A, p.src()); - assertEquals("incorrect dst", H, p.dst()); - assertEquals("incorrect path length", 5, p.edges().size()); - assertEquals("incorrect path cost", 5.0, p.cost(), 0.1); - - paths = search.search(graph, A, G, weight, ALL_PATHS).paths(); - assertEquals("incorrect paths count", 0, paths.size()); - - paths = search.search(graph, A, null, weight, ALL_PATHS).paths(); - printPaths(paths); - assertEquals("incorrect paths count", 6, paths.size()); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/BreadthFirstSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/BreadthFirstSearchTest.java deleted file mode 100644 index 0b574aff..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/BreadthFirstSearchTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import org.junit.Test; - -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.onlab.graph.GraphPathSearch.ALL_PATHS; - -/** - * Test of the BFS and similar path search algorithms. - */ -public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest { - - @Override - protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { - return new BreadthFirstSearch<>(); - } - - @Test - public void defaultGraphTest() { - executeDefaultTest(7, 3, 8.0); - } - - @Test - public void defaultHopCountWeight() { - weight = null; - executeDefaultTest(7, 3, 3.0); - } - - // Executes the default test - protected void executeDefaultTest(int pathCount, int pathLength, double pathCost) { - graph = new AdjacencyListsGraph<>(vertexes(), edges()); - - GraphPathSearch<TestVertex, TestEdge> search = graphSearch(); - Set<Path<TestVertex, TestEdge>> paths = - search.search(graph, A, H, weight, ALL_PATHS).paths(); - assertEquals("incorrect paths count", 1, paths.size()); - - Path p = paths.iterator().next(); - assertEquals("incorrect src", A, p.src()); - assertEquals("incorrect dst", H, p.dst()); - assertEquals("incorrect path length", pathLength, p.edges().size()); - assertEquals("incorrect path cost", pathCost, p.cost(), 0.1); - - paths = search.search(graph, A, null, weight, ALL_PATHS).paths(); - printPaths(paths); - assertEquals("incorrect paths count", pathCount, paths.size()); - } - - // Executes the search and validates its results. - protected void executeSearch(GraphPathSearch<TestVertex, TestEdge> search, - Graph<TestVertex, TestEdge> graph, - TestVertex src, TestVertex dst, - EdgeWeight<TestVertex, TestEdge> weight, - int pathCount, double pathCost) { - GraphPathSearch.Result<TestVertex, TestEdge> result = - search.search(graph, src, dst, weight, ALL_PATHS); - Set<Path<TestVertex, TestEdge>> paths = result.paths(); - printPaths(paths); - assertEquals("incorrect paths count", pathCount, paths.size()); - if (pathCount > 0) { - Path<TestVertex, TestEdge> path = paths.iterator().next(); - assertEquals("incorrect path cost", pathCost, path.cost(), 0.1); - } - } - - // Executes the single-path search and validates its results. - protected void executeSinglePathSearch(GraphPathSearch<TestVertex, TestEdge> search, - Graph<TestVertex, TestEdge> graph, - TestVertex src, TestVertex dst, - EdgeWeight<TestVertex, TestEdge> weight, - int pathCount, double pathCost) { - GraphPathSearch.Result<TestVertex, TestEdge> result = - search.search(graph, src, dst, weight, 1); - Set<Path<TestVertex, TestEdge>> paths = result.paths(); - printPaths(paths); - assertEquals("incorrect paths count", Math.min(pathCount, 1), paths.size()); - if (pathCount > 0) { - Path<TestVertex, TestEdge> path = paths.iterator().next(); - assertEquals("incorrect path cost", pathCost, path.cost(), 0.1); - } - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DefaultMutablePathTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DefaultMutablePathTest.java deleted file mode 100644 index 8eb09df6..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DefaultMutablePathTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import static com.google.common.collect.ImmutableList.of; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -/** - * Test of the default mutable path. - */ -public class DefaultMutablePathTest extends DefaultPathTest { - - @Test - public void equality() { - DefaultPath<TestVertex, TestEdge> p1 = - new DefaultPath<>(of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1)), 2.0); - DefaultPath<TestVertex, TestEdge> p2 = - new DefaultPath<>(of(new TestEdge(A, B, 1), - new TestEdge(B, D, 1)), 2.0); - new EqualsTester().addEqualityGroup(new DefaultMutablePath<>(p1), - new DefaultMutablePath<>(p1)) - .addEqualityGroup(new DefaultMutablePath<>(p2)) - .testEquals(); - } - - @Test - public void empty() { - MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); - assertNull("src should be null", p.src()); - assertNull("dst should be null", p.dst()); - assertEquals("incorrect edge count", 0, p.edges().size()); - assertEquals("incorrect path cost", 0.0, p.cost(), 0.1); - } - - @Test - public void pathCost() { - MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); - p.setCost(4); - assertEquals("incorrect path cost", 4.0, p.cost(), 0.1); - } - - private void validatePath(Path<TestVertex, TestEdge> p, - TestVertex src, TestVertex dst, int length) { - validatePath(p, src, dst, length, 0.0); - } - - @Test - public void insertEdge() { - MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); - p.insertEdge(new TestEdge(B, C, 1)); - p.insertEdge(new TestEdge(A, B, 1)); - validatePath(p, A, C, 2); - } - - @Test - public void appendEdge() { - MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); - p.appendEdge(new TestEdge(A, B, 1)); - p.appendEdge(new TestEdge(B, C, 1)); - validatePath(p, A, C, 2); - } - - @Test - public void removeEdge() { - MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); - p.appendEdge(new TestEdge(A, B, 1)); - p.appendEdge(new TestEdge(B, C, 1)); - p.appendEdge(new TestEdge(C, C, 2)); - p.appendEdge(new TestEdge(C, D, 1)); - validatePath(p, A, D, 4); - - p.removeEdge(new TestEdge(A, B, 1)); - validatePath(p, B, D, 3); - - p.removeEdge(new TestEdge(C, C, 2)); - validatePath(p, B, D, 2); - - p.removeEdge(new TestEdge(C, D, 1)); - validatePath(p, B, C, 1); - } - - @Test - public void toImmutable() { - MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); - p.appendEdge(new TestEdge(A, B, 1)); - p.appendEdge(new TestEdge(B, C, 1)); - validatePath(p, A, C, 2); - - assertEquals("immutables should equal", p.toImmutable(), p.toImmutable()); - validatePath(p.toImmutable(), A, C, 2); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DefaultPathTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DefaultPathTest.java deleted file mode 100644 index 92befbfe..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DefaultPathTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import java.util.List; - -import static com.google.common.collect.ImmutableList.of; -import static org.junit.Assert.assertEquals; - -/** - * Test of the default path. - */ -public class DefaultPathTest extends GraphTest { - - @Test - public void equality() { - List<TestEdge> edges = of(new TestEdge(A, B, 1), new TestEdge(B, C, 1)); - new EqualsTester().addEqualityGroup(new DefaultPath<>(edges, 2.0), - new DefaultPath<>(edges, 2.0)) - .addEqualityGroup(new DefaultPath<>(edges, 3.0)) - .testEquals(); - } - - @Test - public void basics() { - Path<TestVertex, TestEdge> p = new DefaultPath<>(of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1)), 2.0); - validatePath(p, A, C, 2, 2.0); - } - - // Validates the path against expected attributes - protected void validatePath(Path<TestVertex, TestEdge> p, - TestVertex src, TestVertex dst, - int length, double cost) { - assertEquals("incorrect path length", length, p.edges().size()); - assertEquals("incorrect source", src, p.src()); - assertEquals("incorrect destination", dst, p.dst()); - assertEquals("incorrect path cost", cost, p.cost(), 0.1); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DepthFirstSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DepthFirstSearchTest.java deleted file mode 100644 index 3977ebf1..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DepthFirstSearchTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import org.junit.Test; - -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.onlab.graph.DepthFirstSearch.EdgeType; -import static org.onlab.graph.GraphPathSearch.ALL_PATHS; - -/** - * Test of the DFS algorithm. - */ -public class DepthFirstSearchTest extends AbstractGraphPathSearchTest { - - @Override - protected DepthFirstSearch<TestVertex, TestEdge> graphSearch() { - return new DepthFirstSearch<>(); - } - - @Test - public void defaultGraphTest() { - executeDefaultTest(3, 6, 5.0, 12.0); - executeBroadSearch(); - } - - @Test - public void defaultHopCountWeight() { - weight = null; - executeDefaultTest(3, 6, 3.0, 6.0); - executeBroadSearch(); - } - - protected void executeDefaultTest(int minLength, int maxLength, - double minCost, double maxCost) { - graph = new AdjacencyListsGraph<>(vertexes(), edges()); - DepthFirstSearch<TestVertex, TestEdge> search = graphSearch(); - - DepthFirstSearch<TestVertex, TestEdge>.SpanningTreeResult result = - search.search(graph, A, H, weight, 1); - Set<Path<TestVertex, TestEdge>> paths = result.paths(); - assertEquals("incorrect path count", 1, paths.size()); - - Path path = paths.iterator().next(); - System.out.println(path); - assertEquals("incorrect src", A, path.src()); - assertEquals("incorrect dst", H, path.dst()); - - int l = path.edges().size(); - assertTrue("incorrect path length " + l, - minLength <= l && l <= maxLength); - assertTrue("incorrect path cost " + path.cost(), - minCost <= path.cost() && path.cost() <= maxCost); - - System.out.println(result.edges()); - printPaths(paths); - } - - public void executeBroadSearch() { - graph = new AdjacencyListsGraph<>(vertexes(), edges()); - DepthFirstSearch<TestVertex, TestEdge> search = graphSearch(); - - // Perform narrow path search to a specific destination. - DepthFirstSearch<TestVertex, TestEdge>.SpanningTreeResult result = - search.search(graph, A, null, weight, ALL_PATHS); - assertEquals("incorrect paths count", 7, result.paths().size()); - - int[] types = new int[]{0, 0, 0, 0}; - for (EdgeType t : result.edges().values()) { - types[t.ordinal()] += 1; - } - assertEquals("incorrect tree-edge count", 7, - types[EdgeType.TREE_EDGE.ordinal()]); - assertEquals("incorrect back-edge count", 1, - types[EdgeType.BACK_EDGE.ordinal()]); - assertEquals("incorrect cross-edge & forward-edge count", 4, - types[EdgeType.FORWARD_EDGE.ordinal()] + - types[EdgeType.CROSS_EDGE.ordinal()]); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DijkstraGraphSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DijkstraGraphSearchTest.java deleted file mode 100644 index 17f08225..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DijkstraGraphSearchTest.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import org.junit.Test; - -import java.text.DecimalFormat; -import java.util.HashSet; -import java.util.Set; - -import static com.google.common.collect.ImmutableSet.of; -import static org.junit.Assert.assertEquals; - -/** - * Test of the Dijkstra algorithm. - */ -public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { - - @Override - protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { - return new DijkstraGraphSearch<>(); - } - - @Test - @Override - public void defaultGraphTest() { - executeDefaultTest(7, 5, 5.0); - } - - @Test - @Override - public void defaultHopCountWeight() { - weight = null; - executeDefaultTest(10, 3, 3.0); - } - - @Test - public void noPath() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(new TestEdge(A, B, 1), - new TestEdge(B, A, 1), - new TestEdge(C, D, 1), - new TestEdge(D, C, 1))); - GraphPathSearch<TestVertex, TestEdge> gs = graphSearch(); - Set<Path<TestVertex, TestEdge>> paths = gs.search(graph, A, B, weight, 1).paths(); - printPaths(paths); - assertEquals("incorrect paths count", 1, paths.size()); - assertEquals("incorrect path cost", 1.0, paths.iterator().next().cost(), 0.1); - - paths = gs.search(graph, A, D, weight, 1).paths(); - printPaths(paths); - assertEquals("incorrect paths count", 0, paths.size()); - - paths = gs.search(graph, A, null, weight, 1).paths(); - printPaths(paths); - assertEquals("incorrect paths count", 1, paths.size()); - assertEquals("incorrect path cost", 1.0, paths.iterator().next().cost(), 0.1); - } - - @Test - public void simpleMultiplePath() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(new TestEdge(A, B, 1), - new TestEdge(A, C, 1), - new TestEdge(B, D, 1), - new TestEdge(C, D, 1))); - executeSearch(graphSearch(), graph, A, D, weight, 2, 2.0); - executeSinglePathSearch(graphSearch(), graph, A, D, weight, 1, 2.0); - } - - @Test - public void denseMultiplePath() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G), - of(new TestEdge(A, B, 1), - new TestEdge(A, C, 1), - new TestEdge(B, D, 1), - new TestEdge(C, D, 1), - new TestEdge(D, E, 1), - new TestEdge(D, F, 1), - new TestEdge(E, G, 1), - new TestEdge(F, G, 1), - new TestEdge(A, G, 4))); - executeSearch(graphSearch(), graph, A, G, weight, 5, 4.0); - executeSinglePathSearch(graphSearch(), graph, A, G, weight, 1, 4.0); - } - - @Test - public void dualEdgeMultiplePath() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G, H), - of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), - new TestEdge(B, D, 2), new TestEdge(B, C, 1), - new TestEdge(B, E, 4), new TestEdge(C, E, 1), - new TestEdge(D, H, 5), new TestEdge(D, E, 1), - new TestEdge(E, F, 1), new TestEdge(F, D, 1), - new TestEdge(F, G, 1), new TestEdge(F, H, 1), - new TestEdge(A, E, 3), new TestEdge(B, D, 1))); - executeSearch(graphSearch(), graph, A, E, weight, 3, 3.0); - executeSinglePathSearch(graphSearch(), graph, A, E, weight, 1, 3.0); - } - - @Test - public void negativeWeights() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G), - of(new TestEdge(A, B, 1), - new TestEdge(A, C, -1), - new TestEdge(B, D, 1), - new TestEdge(D, A, -2), - new TestEdge(C, D, 1), - new TestEdge(D, E, 1), - new TestEdge(D, F, 1), - new TestEdge(E, G, 1), - new TestEdge(F, G, 1), - new TestEdge(G, A, -5), - new TestEdge(A, G, 4))); - executeSearch(graphSearch(), graph, A, G, weight, 3, 4.0); - executeSinglePathSearch(graphSearch(), graph, A, G, weight, 1, 4.0); - } - - @Test - public void disconnectedPerf() { - disconnected(); - disconnected(); - disconnected(); - disconnected(); - disconnected(); - disconnected(); - disconnected(); - disconnected(); - disconnected(); - disconnected(); - } - - - @Test - public void disconnected() { - Set<TestVertex> vertexes = new HashSet<>(); - for (int i = 0; i < 200; i++) { - vertexes.add(new TestVertex("v" + i)); - } - - graph = new AdjacencyListsGraph<>(vertexes, of()); - - long start = System.nanoTime(); - for (TestVertex src : vertexes) { - executeSearch(graphSearch(), graph, src, null, null, 0, 0); - } - long end = System.nanoTime(); - DecimalFormat fmt = new DecimalFormat("#,###"); - System.out.println("Compute cost is " + fmt.format(end - start) + " nanos"); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DisjointPathPairTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DisjointPathPairTest.java deleted file mode 100644 index ca6c56c4..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/DisjointPathPairTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.onlab.graph; - -import static org.junit.Assert.*; - -import org.junit.Test; - -import com.google.common.collect.ImmutableList; -import com.google.common.testing.EqualsTester; - -/** - * Test of DisjointPathPair. - */ -public class DisjointPathPairTest { - - private static final TestVertex A = new TestVertex("A"); - private static final TestVertex B = new TestVertex("B"); - private static final TestVertex C = new TestVertex("C"); - private static final TestVertex D = new TestVertex("D"); - - private static final TestEdge AB = new TestEdge(A, B, 1.0); - private static final TestEdge BC = new TestEdge(B, C, 1.0); - private static final TestEdge AD = new TestEdge(A, D, 1.0); - private static final TestEdge DC = new TestEdge(D, C, 1.0); - - private static final Path<TestVertex, TestEdge> ABC - = new DefaultPath<>(ImmutableList.of(AB, BC), 1.0); - private static final Path<TestVertex, TestEdge> ADC - = new DefaultPath<>(ImmutableList.of(AD, DC), 1.0); - - @Test - public void testSwappingPrimarySecondaryDoesntImpactHashCode() { - assertEquals(new DisjointPathPair<>(ABC, ADC).hashCode(), - new DisjointPathPair<>(ADC, ABC).hashCode()); - } - - @Test - public void testSwappingPrimarySecondaryDoesntImpactEquality() { - new EqualsTester() - .addEqualityGroup(new DisjointPathPair<>(ABC, ADC), - new DisjointPathPair<>(ADC, ABC)); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/GraphTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/GraphTest.java deleted file mode 100644 index d29282fc..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/GraphTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.Set; - -import static com.google.common.collect.ImmutableSet.of; - -/** - * Base class for various graph-related tests. - */ -public class GraphTest { - - static final TestVertex A = new TestVertex("A"); - static final TestVertex B = new TestVertex("B"); - static final TestVertex C = new TestVertex("C"); - static final TestVertex D = new TestVertex("D"); - static final TestVertex E = new TestVertex("E"); - static final TestVertex F = new TestVertex("F"); - static final TestVertex G = new TestVertex("G"); - static final TestVertex H = new TestVertex("H"); - static final TestVertex Z = new TestVertex("Z"); - - protected Graph<TestVertex, TestEdge> graph; - - protected EdgeWeight<TestVertex, TestEdge> weight = - new EdgeWeight<TestVertex, TestEdge>() { - @Override - public double weight(TestEdge edge) { - return edge.weight(); - } - }; - - protected void printPaths(Set<Path<TestVertex, TestEdge>> paths) { - for (Path p : paths) { - System.out.println(p); - } - } - - protected Set<TestVertex> vertexes() { - return of(A, B, C, D, E, F, G, H); - } - - protected Set<TestEdge> edges() { - return of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), - new TestEdge(B, D, 2), new TestEdge(B, C, 1), - new TestEdge(B, E, 4), new TestEdge(C, E, 1), - new TestEdge(D, H, 5), new TestEdge(D, E, 1), - new TestEdge(E, F, 1), new TestEdge(F, D, 1), - new TestEdge(F, G, 1), new TestEdge(F, H, 1)); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/HeapTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/HeapTest.java deleted file mode 100644 index f34185e2..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/HeapTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import com.google.common.collect.Ordering; -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Comparator; - -import static com.google.common.collect.ImmutableList.of; -import static org.junit.Assert.*; - -/** - * Heap data structure tests. - */ -public class HeapTest { - - private ArrayList<Integer> data = - new ArrayList<>(of(6, 4, 5, 9, 8, 3, 2, 1, 7, 0)); - - private static final Comparator<Integer> MIN = Ordering.natural().reverse(); - private static final Comparator<Integer> MAX = Ordering.natural(); - - @Test - public void equality() { - new EqualsTester() - .addEqualityGroup(new Heap<>(data, MIN), - new Heap<>(data, MIN)) - .addEqualityGroup(new Heap<>(data, MAX)) - .testEquals(); - } - - @Test - public void empty() { - Heap<Integer> h = new Heap<>(new ArrayList<Integer>(), MIN); - assertTrue("should be empty", h.isEmpty()); - assertEquals("incorrect size", 0, h.size()); - assertNull("no item expected", h.extreme()); - assertNull("no item expected", h.extractExtreme()); - } - - @Test - public void insert() { - Heap<Integer> h = new Heap<>(data, MIN); - assertEquals("incorrect size", 10, h.size()); - h.insert(3); - assertEquals("incorrect size", 11, h.size()); - } - - @Test - public void minQueue() { - Heap<Integer> h = new Heap<>(data, MIN); - assertFalse("should not be empty", h.isEmpty()); - assertEquals("incorrect size", 10, h.size()); - assertEquals("incorrect extreme", (Integer) 0, h.extreme()); - - for (int i = 0, n = h.size(); i < n; i++) { - assertEquals("incorrect element", (Integer) i, h.extractExtreme()); - } - assertTrue("should be empty", h.isEmpty()); - } - - @Test - public void maxQueue() { - Heap<Integer> h = new Heap<>(data, MAX); - assertFalse("should not be empty", h.isEmpty()); - assertEquals("incorrect size", 10, h.size()); - assertEquals("incorrect extreme", (Integer) 9, h.extreme()); - - for (int i = h.size(); i > 0; i--) { - assertEquals("incorrect element", (Integer) (i - 1), h.extractExtreme()); - } - assertTrue("should be empty", h.isEmpty()); - } - - @Test - public void iterator() { - Heap<Integer> h = new Heap<>(data, MIN); - assertTrue("should have next element", h.iterator().hasNext()); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/KshortestPathSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/KshortestPathSearchTest.java deleted file mode 100644 index 3e8900b8..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/KshortestPathSearchTest.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import static com.google.common.collect.ImmutableSet.of; -import static org.junit.Assert.*; - -import java.io.ByteArrayOutputStream; -//import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -public class KshortestPathSearchTest extends BreadthFirstSearchTest { - - private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - - @Test - public void noPath() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(new TestEdge(A, B, 1), - new TestEdge(B, A, 1), - new TestEdge(C, D, 1), - new TestEdge(D, C, 1))); - KshortestPathSearch<TestVertex, TestEdge> gs = new KshortestPathSearch<TestVertex, TestEdge>(graph); - List<List<TestEdge>> result = gs.search(A, D, weight, 1); - List<Path> paths = new ArrayList<>(); - Iterator<List<TestEdge>> itr = result.iterator(); - while (itr.hasNext()) { - System.out.println(itr.next().toString()); - } - assertEquals("incorrect paths count", 0, result.size()); - } - - @Test - public void test2Path() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(new TestEdge(A, B, 1), - new TestEdge(B, A, 1), - new TestEdge(B, D, 1), - new TestEdge(D, B, 1), - new TestEdge(A, C, 1), - new TestEdge(C, A, 1), - new TestEdge(C, D, 1), - new TestEdge(D, C, 1))); - KshortestPathSearch<TestVertex, TestEdge> gs = new KshortestPathSearch<TestVertex, TestEdge>(graph); - List<List<TestEdge>> result = gs.search(A, D, weight, 2); - List<Path> paths = new ArrayList<>(); - Iterator<List<TestEdge>> itr = result.iterator(); - while (itr.hasNext()) { - System.out.println(itr.next().toString()); - } - assertEquals("incorrect paths count", 2, result.size()); - // assertEquals("printing the paths", outContent.toString()); - } - - @Test - public void test3Path() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(new TestEdge(A, B, 1), - new TestEdge(B, A, 1), - new TestEdge(A, D, 1), - new TestEdge(D, A, 1), - new TestEdge(B, D, 1), - new TestEdge(D, B, 1), - new TestEdge(A, C, 1), - new TestEdge(C, A, 1), - new TestEdge(C, D, 1), - new TestEdge(D, C, 1))); - KshortestPathSearch<TestVertex, TestEdge> gs = new KshortestPathSearch<TestVertex, TestEdge>(graph); - List<List<TestEdge>> result = gs.search(A, D, weight, 3); - List<Path> paths = new ArrayList<>(); - Iterator<List<TestEdge>> itr = result.iterator(); - while (itr.hasNext()) { - System.out.println(itr.next().toString()); - } - assertEquals("incorrect paths count", 3, result.size()); - // assertEquals("printing the paths", outContent.toString()); - } - - @Test - public void test4Path() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D, E, F), - of(new TestEdge(A, B, 1), - new TestEdge(B, A, 1), - new TestEdge(A, C, 1), - new TestEdge(C, A, 1), - new TestEdge(B, D, 1), - new TestEdge(D, B, 1), - new TestEdge(C, E, 1), - new TestEdge(E, C, 1), - new TestEdge(D, F, 1), - new TestEdge(F, D, 1), - new TestEdge(F, E, 1), - new TestEdge(E, F, 1), - new TestEdge(C, D, 1), - new TestEdge(D, C, 1))); - KshortestPathSearch<TestVertex, TestEdge> gs = new KshortestPathSearch<TestVertex, TestEdge>(graph); - List<List<TestEdge>> result = gs.search(A, F, weight, 4); - List<Path> paths = new ArrayList<>(); - Iterator<List<TestEdge>> itr = result.iterator(); - while (itr.hasNext()) { - System.out.println(itr.next().toString()); - } - assertEquals("incorrect paths count", 4, result.size()); - // assertEquals("printing the paths", outContent.toString()); - } - - @Test - public void test6Path() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D, E, F), - of(new TestEdge(A, B, 1), - new TestEdge(B, A, 1), - new TestEdge(A, C, 1), - new TestEdge(C, A, 1), - new TestEdge(B, D, 1), - new TestEdge(D, B, 1), - new TestEdge(B, C, 1), - new TestEdge(C, B, 1), - new TestEdge(D, E, 1), - new TestEdge(E, D, 1), - new TestEdge(C, E, 1), - new TestEdge(E, C, 1), - new TestEdge(D, F, 1), - new TestEdge(F, D, 1), - new TestEdge(E, F, 1), - new TestEdge(F, E, 1))); - KshortestPathSearch<TestVertex, TestEdge> gs = new KshortestPathSearch<TestVertex, TestEdge>(graph); - List<List<TestEdge>> result = gs.search(A, F, weight, 6); - List<Path> paths = new ArrayList<>(); - Iterator<List<TestEdge>> itr = result.iterator(); - while (itr.hasNext()) { - System.out.println(itr.next().toString()); - } - assertEquals("incorrect paths count", 6, result.size()); - // assertEquals("printing the paths", outContent.toString()); - } - - @Test - public void dualEdgePath() { - graph = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G, H), - of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), - new TestEdge(B, D, 2), new TestEdge(B, C, 1), - new TestEdge(B, E, 4), new TestEdge(C, E, 1), - new TestEdge(D, H, 5), new TestEdge(D, E, 1), - new TestEdge(E, F, 1), new TestEdge(F, D, 1), - new TestEdge(F, G, 1), new TestEdge(F, H, 1), - new TestEdge(A, E, 3), new TestEdge(B, D, 1))); - KshortestPathSearch<TestVertex, TestEdge> gs = new KshortestPathSearch<TestVertex, TestEdge>(graph); - List<List<TestEdge>> result = gs.search(A, G, weight, 6); - List<Path> paths = new ArrayList<>(); - Iterator<List<TestEdge>> itr = result.iterator(); - while (itr.hasNext()) { - System.out.println(itr.next().toString()); - } - assertEquals("incorrect paths count", 6, result.size()); - // assertEquals("printing the paths", outContent.toString()); - } - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - } - - @Before - public void setUp() throws Exception { - // System.setOut(new PrintStream(outContent)); - } - - @After - public void tearDown() throws Exception { - // System.setOut(null); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SrlgGraphSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SrlgGraphSearchTest.java deleted file mode 100644 index 26d50364..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SrlgGraphSearchTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.graph; - -import org.junit.Test; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import static com.google.common.collect.ImmutableSet.of; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.onlab.graph.GraphPathSearch.ALL_PATHS; - -/** - * Test of the Suurballe backup path algorithm. - */ -public class SrlgGraphSearchTest extends BreadthFirstSearchTest { - - @Override - protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { - return new SrlgGraphSearch<>(null); - } - - public void setDefaultWeights() { - weight = null; - } - - @Override - public void defaultGraphTest() { - } - - @Override - public void defaultHopCountWeight() { - } - - @Test - public void onePathPair() { - setDefaultWeights(); - TestEdge aB = new TestEdge(A, B, 1); - TestEdge bC = new TestEdge(B, C, 1); - TestEdge aD = new TestEdge(A, D, 1); - TestEdge dC = new TestEdge(D, C, 1); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(aB, bC, aD, dC)); - Map<TestEdge, Integer> riskProfile = new HashMap<>(); - riskProfile.put(aB, 0); - riskProfile.put(bC, 0); - riskProfile.put(aD, 1); - riskProfile.put(dC, 1); - SrlgGraphSearch<TestVertex, TestEdge> search = new SrlgGraphSearch<>(2, riskProfile); - Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, C, weight, ALL_PATHS).paths(); - System.out.println("\n\n\n" + paths + "\n\n\n"); - assertEquals("one disjoint path pair found", 1, paths.size()); - checkIsDisjoint(paths.iterator().next(), riskProfile); - } - - public void checkIsDisjoint(Path<TestVertex, TestEdge> p, Map<TestEdge, Integer> risks) { - assertTrue("The path is not a DisjointPathPair", (p instanceof DisjointPathPair)); - DisjointPathPair<TestVertex, TestEdge> q = (DisjointPathPair) p; - Set<Integer> p1Risks = new HashSet<>(); - for (TestEdge e : q.edges()) { - p1Risks.add(risks.get(e)); - } - if (!q.hasBackup()) { - return; - } - Path<TestVertex, TestEdge> pq = q.secondary(); - for (TestEdge e: pq.edges()) { - assertTrue("The paths are not disjoint", !p1Risks.contains(risks.get(e))); - } - } - - @Test - public void complexGraphTest() { - setDefaultWeights(); - TestEdge aB = new TestEdge(A, B, 1); - TestEdge bC = new TestEdge(B, C, 1); - TestEdge aD = new TestEdge(A, D, 1); - TestEdge dC = new TestEdge(D, C, 1); - TestEdge cE = new TestEdge(C, E, 1); - TestEdge bE = new TestEdge(B, E, 1); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), - of(aB, bC, aD, dC, cE, bE)); - Map<TestEdge, Integer> riskProfile = new HashMap<>(); - riskProfile.put(aB, 0); - riskProfile.put(bC, 0); - riskProfile.put(aD, 1); - riskProfile.put(dC, 1); - riskProfile.put(cE, 2); - riskProfile.put(bE, 3); - SrlgGraphSearch<TestVertex, TestEdge> search = new SrlgGraphSearch<>(4, riskProfile); - search.search(graph, A, E, weight, ALL_PATHS).paths(); - } - - @Test - public void multiplePathGraphTest() { - setDefaultWeights(); - TestEdge aB = new TestEdge(A, B, 1); - TestEdge bE = new TestEdge(B, E, 1); - TestEdge aD = new TestEdge(A, D, 1); - TestEdge dE = new TestEdge(D, E, 1); - TestEdge aC = new TestEdge(A, C, 1); - TestEdge cE = new TestEdge(C, E, 1); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), - of(aB, bE, aD, dE, aC, cE)); - Map<TestEdge, Integer> riskProfile = new HashMap<>(); - riskProfile.put(aB, 0); - riskProfile.put(bE, 1); - riskProfile.put(aD, 2); - riskProfile.put(dE, 3); - riskProfile.put(aC, 4); - riskProfile.put(cE, 5); - SrlgGraphSearch<TestVertex, TestEdge> search = new SrlgGraphSearch<>(6, riskProfile); - Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, ALL_PATHS).paths(); - assertTrue("> one disjoint path pair found", paths.size() >= 1); - checkIsDisjoint(paths.iterator().next(), riskProfile); - } - - @Test - public void onePath() { - setDefaultWeights(); - TestEdge aB = new TestEdge(A, B, 1); - TestEdge bC = new TestEdge(B, C, 1); - TestEdge aD = new TestEdge(A, D, 1); - TestEdge dC = new TestEdge(D, C, 1); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(aB, bC, aD, dC)); - Map<TestEdge, Integer> riskProfile = new HashMap<>(); - riskProfile.put(aB, 0); - riskProfile.put(bC, 0); - riskProfile.put(aD, 1); - riskProfile.put(dC, 0); - SrlgGraphSearch<TestVertex, TestEdge> search = new SrlgGraphSearch<>(2, riskProfile); - Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, C, weight, ALL_PATHS).paths(); - System.out.println(paths); - assertTrue("no disjoint path pairs found", paths.size() == 0); - } - - @Test - public void noPath() { - setDefaultWeights(); - TestEdge aB = new TestEdge(A, B, 1); - TestEdge bC = new TestEdge(B, C, 1); - TestEdge aD = new TestEdge(A, D, 1); - TestEdge dC = new TestEdge(D, C, 1); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), - of(aB, bC, aD, dC)); - Map<TestEdge, Integer> riskProfile = new HashMap<>(); - riskProfile.put(aB, 0); - riskProfile.put(bC, 0); - riskProfile.put(aD, 1); - riskProfile.put(dC, 0); - SrlgGraphSearch<TestVertex, TestEdge> search = new SrlgGraphSearch<>(2, riskProfile); - Set<Path<TestVertex, TestEdge>> paths = search.search(graph, A, E, weight, ALL_PATHS).paths(); - assertTrue("no disjoint path pairs found", paths.size() == 0); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SuurballeGraphSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SuurballeGraphSearchTest.java deleted file mode 100644 index 0d2d13b0..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/SuurballeGraphSearchTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import org.junit.Test; -import java.util.Set; - -import static com.google.common.collect.ImmutableSet.of; -import static org.junit.Assert.assertEquals; -//import static org.junit.Assert.assertTrue; - - - -/** - * Test of the Suurballe backup path algorithm. - */ -public class SuurballeGraphSearchTest extends BreadthFirstSearchTest { - - @Override - protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { - return new SuurballeGraphSearch<>(); - } - - public void setWeights() { - weight = new EdgeWeight<TestVertex, TestEdge>() { - @Override - public double weight(TestEdge edge) { - return edge.weight(); - } - }; - } - public void setDefaultWeights() { - weight = null; - } - @Override - public void defaultGraphTest() { - - } - - @Override - public void defaultHopCountWeight() { - - } - - @Test - public void basicGraphTest() { - setDefaultWeights(); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(A, D, 1), - new TestEdge(D, C, 1))); - executeSearch(graphSearch(), graph, A, C, weight, 1, 4.0); - } - - @Test - public void multiplePathOnePairGraphTest() { - setWeights(); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(A, D, 1), - new TestEdge(D, C, 1), - new TestEdge(B, E, 2), - new TestEdge(C, E, 1))); - executeSearch(graphSearch(), graph, A, E, weight, 1, 6.0); - } - - @Test - public void multiplePathsMultiplePairs() { - setWeights(); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), - of(new TestEdge(A, B, 1), - new TestEdge(B, E, 1), - new TestEdge(A, C, 1), - new TestEdge(C, E, 1), - new TestEdge(A, D, 1), - new TestEdge(D, E, 1), - new TestEdge(A, E, 2))); - GraphPathSearch.Result<TestVertex, TestEdge> result = - graphSearch().search(graph, A, E, weight, GraphPathSearch.ALL_PATHS); - Set<Path<TestVertex, TestEdge>> paths = result.paths(); - System.out.println("\n\n" + paths + "\n\n\ndone\n"); - assertEquals("incorrect paths count", 3, paths.size()); - DisjointPathPair<TestVertex, TestEdge> dpp = (DisjointPathPair<TestVertex, TestEdge>) paths.iterator().next(); - assertEquals("incorrect disjoint paths per path", 2, dpp.size()); - } - - @Test - public void differingPrimaryAndBackupPathLengths() { - setWeights(); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D, E), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(A, D, 1), - new TestEdge(D, C, 1), - new TestEdge(B, E, 1), - new TestEdge(C, E, 1))); - executeSearch(graphSearch(), graph, A, E, weight, 1, 5.0); - } - - @Test - public void onePath() { - setWeights(); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(A, C, 4), - new TestEdge(C, D, 1))); - GraphPathSearch.Result<TestVertex, TestEdge> result = - graphSearch().search(graph, A, D, weight, GraphPathSearch.ALL_PATHS); - Set<Path<TestVertex, TestEdge>> paths = result.paths(); - assertEquals("incorrect paths count", 1, paths.size()); - DisjointPathPair<TestVertex, TestEdge> dpp = (DisjointPathPair<TestVertex, TestEdge>) paths.iterator().next(); - assertEquals("incorrect disjoint paths count", 1, dpp.size()); - } - - @Test - public void noPath() { - setWeights(); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(A, C, 4))); - GraphPathSearch.Result<TestVertex, TestEdge> result = - graphSearch().search(graph, A, D, weight, GraphPathSearch.ALL_PATHS); - Set<Path<TestVertex, TestEdge>> paths = result.paths(); - assertEquals("incorrect paths count", paths.size(), 0); - } - - @Test - public void disconnected() { - setWeights(); - Graph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(of(A, B, C, D), - of()); - GraphPathSearch.Result<TestVertex, TestEdge> result = - graphSearch().search(graph, A, D, weight, GraphPathSearch.ALL_PATHS); - Set<Path<TestVertex, TestEdge>> paths = result.paths(); - assertEquals("incorrect paths count", 0, paths.size()); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TarjanGraphSearchTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TarjanGraphSearchTest.java deleted file mode 100644 index 40f90513..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TarjanGraphSearchTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import org.junit.Test; - -import static com.google.common.collect.ImmutableSet.of; -import static org.junit.Assert.assertEquals; -import static org.onlab.graph.TarjanGraphSearch.SccResult; - -/** - * Tarjan graph search tests. - */ -public class TarjanGraphSearchTest extends GraphTest { - - private void validate(SccResult<TestVertex, TestEdge> result, int cc) { - System.out.println("Cluster count: " + result.clusterVertexes().size()); - System.out.println("Clusters: " + result.clusterVertexes()); - assertEquals("incorrect cluster count", cc, result.clusterCount()); - } - - private void validate(SccResult<TestVertex, TestEdge> result, - int i, int vc, int ec) { - assertEquals("incorrect cluster count", vc, result.clusterVertexes().get(i).size()); - assertEquals("incorrect edge count", ec, result.clusterEdges().get(i).size()); - } - - @Test - public void basic() { - graph = new AdjacencyListsGraph<>(vertexes(), edges()); - TarjanGraphSearch<TestVertex, TestEdge> gs = new TarjanGraphSearch<>(); - SccResult<TestVertex, TestEdge> result = gs.search(graph, null); - validate(result, 6); - } - - @Test - public void singleCluster() { - graph = new AdjacencyListsGraph<>(vertexes(), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(C, D, 1), - new TestEdge(D, E, 1), - new TestEdge(E, F, 1), - new TestEdge(F, G, 1), - new TestEdge(G, H, 1), - new TestEdge(H, A, 1))); - - TarjanGraphSearch<TestVertex, TestEdge> gs = new TarjanGraphSearch<>(); - SccResult<TestVertex, TestEdge> result = gs.search(graph, null); - validate(result, 1); - validate(result, 0, 8, 8); - } - - @Test - public void twoUnconnectedCluster() { - graph = new AdjacencyListsGraph<>(vertexes(), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(C, D, 1), - new TestEdge(D, A, 1), - new TestEdge(E, F, 1), - new TestEdge(F, G, 1), - new TestEdge(G, H, 1), - new TestEdge(H, E, 1))); - TarjanGraphSearch<TestVertex, TestEdge> gs = new TarjanGraphSearch<>(); - SccResult<TestVertex, TestEdge> result = gs.search(graph, null); - validate(result, 2); - validate(result, 0, 4, 4); - validate(result, 1, 4, 4); - } - - @Test - public void twoWeaklyConnectedClusters() { - graph = new AdjacencyListsGraph<>(vertexes(), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(C, D, 1), - new TestEdge(D, A, 1), - new TestEdge(E, F, 1), - new TestEdge(F, G, 1), - new TestEdge(G, H, 1), - new TestEdge(H, E, 1), - new TestEdge(B, E, 1))); - TarjanGraphSearch<TestVertex, TestEdge> gs = new TarjanGraphSearch<>(); - SccResult<TestVertex, TestEdge> result = gs.search(graph, null); - validate(result, 2); - validate(result, 0, 4, 4); - validate(result, 1, 4, 4); - } - - @Test - public void twoClustersConnectedWithIgnoredEdges() { - graph = new AdjacencyListsGraph<>(vertexes(), - of(new TestEdge(A, B, 1), - new TestEdge(B, C, 1), - new TestEdge(C, D, 1), - new TestEdge(D, A, 1), - new TestEdge(E, F, 1), - new TestEdge(F, G, 1), - new TestEdge(G, H, 1), - new TestEdge(H, E, 1), - new TestEdge(B, E, -1), - new TestEdge(E, B, -1))); - - TarjanGraphSearch<TestVertex, TestEdge> gs = new TarjanGraphSearch<>(); - SccResult<TestVertex, TestEdge> result = gs.search(graph, weight); - validate(result, 2); - validate(result, 0, 4, 4); - validate(result, 1, 4, 4); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TestEdge.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TestEdge.java deleted file mode 100644 index 951f655b..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TestEdge.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.Objects; - -import static com.google.common.base.MoreObjects.toStringHelper; - -/** - * Test edge. - */ -public class TestEdge extends AbstractEdge<TestVertex> { - - private final double weight; - - /** - * Creates a new edge between the specified source and destination vertexes. - * - * @param src source vertex - * @param dst destination vertex - * @param weight edge weight - */ - public TestEdge(TestVertex src, TestVertex dst, double weight) { - super(src, dst); - this.weight = weight; - } - - /** - * Returns the edge weight. - * - * @return edge weight - */ - public double weight() { - return weight; - } - - @Override - public int hashCode() { - return 31 * super.hashCode() + Objects.hash(weight); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof TestEdge) { - final TestEdge other = (TestEdge) obj; - return super.equals(obj) && Objects.equals(this.weight, other.weight); - } - return false; - } - - @Override - public String toString() { - return toStringHelper(this).add("src", src()).add("dst", dst()). - add("weight", weight).toString(); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TestVertex.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TestVertex.java deleted file mode 100644 index b0b92a4a..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/graph/TestVertex.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.graph; - -import java.util.Objects; - -/** - * Test vertex. - */ -public class TestVertex implements Vertex { - - private final String name; - - public TestVertex(String name) { - this.name = name; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof TestVertex) { - final TestVertex other = (TestVertex) obj; - return Objects.equals(this.name, other.name); - } - return false; - } - - @Override - public String toString() { - return name; - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ArpTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ArpTest.java deleted file mode 100644 index 62246245..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ArpTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Unit tests for the ARP class. - */ -public class ArpTest { - - private Deserializer<ARP> deserializer = ARP.deserializer(); - - private final byte hwAddressLength = 6; - private final byte protoAddressLength = 4; - - private MacAddress srcMac = MacAddress.valueOf(1); - private MacAddress targetMac = MacAddress.valueOf(2); - private Ip4Address srcIp = Ip4Address.valueOf(1); - private Ip4Address targetIp = Ip4Address.valueOf(2); - - private byte[] byteHeader; - - @Before - public void setUp() { - ByteBuffer bb = ByteBuffer.allocate(ARP.INITIAL_HEADER_LENGTH + - 2 * hwAddressLength + 2 * protoAddressLength); - bb.putShort(ARP.HW_TYPE_ETHERNET); - bb.putShort(ARP.PROTO_TYPE_IP); - bb.put(hwAddressLength); - bb.put(protoAddressLength); - bb.putShort(ARP.OP_REPLY); - - bb.put(srcMac.toBytes()); - bb.put(srcIp.toOctets()); - bb.put(targetMac.toBytes()); - bb.put(targetIp.toOctets()); - - byteHeader = bb.array(); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, byteHeader); - } - - @Test - public void testDeserialize() throws Exception { - ARP arp = deserializer.deserialize(byteHeader, 0, byteHeader.length); - - assertEquals(ARP.HW_TYPE_ETHERNET, arp.getHardwareType()); - assertEquals(ARP.PROTO_TYPE_IP, arp.getProtocolType()); - assertEquals(hwAddressLength, arp.getHardwareAddressLength()); - assertEquals(protoAddressLength, arp.getProtocolAddressLength()); - assertEquals(ARP.OP_REPLY, arp.getOpCode()); - - assertTrue(Arrays.equals(srcMac.toBytes(), arp.getSenderHardwareAddress())); - assertTrue(Arrays.equals(srcIp.toOctets(), arp.getSenderProtocolAddress())); - assertTrue(Arrays.equals(targetMac.toBytes(), arp.getTargetHardwareAddress())); - assertTrue(Arrays.equals(targetIp.toOctets(), arp.getTargetProtocolAddress())); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/DhcpTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/DhcpTest.java deleted file mode 100644 index aac81412..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/DhcpTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import com.google.common.base.Charsets; -import org.junit.Before; -import org.junit.Test; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Unit tests for DHCP class. - */ -public class DhcpTest { - - private Deserializer<DHCP> deserializer = DHCP.deserializer(); - - private byte opCode = 1; - private byte hardwareType = 1; - private byte hardwareAddressLength = Ethernet.DATALAYER_ADDRESS_LENGTH; - private byte hops = 0; - private int transactionId = 0x2ed4eb50; - private short seconds = 0; - private short flags = 0; - private int clientIpAddress = 1; - private int yourIpAddress = 2; - private int serverIpAddress = 3; - private int gatewayIpAddress = 4; - private byte[] clientHardwareAddress = MacAddress.valueOf(500).toBytes(); - private String serverName = "test-server"; - private String bootFileName = "test-file"; - - private String hostName = "test-host"; - private DHCPOption hostNameOption = new DHCPOption(); - - private byte[] byteHeader; - - @Before - public void setUp() { - hostNameOption.setCode((byte) 55); - hostNameOption.setLength((byte) hostName.length()); - hostNameOption.setData(hostName.getBytes(Charsets.US_ASCII)); - - // Packet length is the fixed DHCP header plus option length plus an - // extra byte to indicate 'end of options'. - ByteBuffer bb = ByteBuffer.allocate(DHCP.MIN_HEADER_LENGTH + - 2 + hostNameOption.getLength() + 1); - - bb.put(opCode); - bb.put(hardwareType); - bb.put(hardwareAddressLength); - bb.put(hops); - bb.putInt(transactionId); - bb.putShort(seconds); - bb.putShort(flags); - bb.putInt(clientIpAddress); - bb.putInt(yourIpAddress); - bb.putInt(serverIpAddress); - bb.putInt(gatewayIpAddress); - bb.put(clientHardwareAddress); - - // need 16 bytes of zeros to pad out the client hardware address field - bb.put(new byte[16 - hardwareAddressLength]); - - // Put server name and pad out to 64 bytes - bb.put(serverName.getBytes(Charsets.US_ASCII)); - bb.put(new byte[64 - serverName.length()]); - - // Put boot file name and pad out to 128 bytes - bb.put(bootFileName.getBytes(Charsets.US_ASCII)); - bb.put(new byte[128 - bootFileName.length()]); - - // Magic cookie - bb.put("DHCP".getBytes(Charsets.US_ASCII)); - - bb.put(hostNameOption.getCode()); - bb.put(hostNameOption.getLength()); - bb.put(hostNameOption.getData()); - - // End of options marker - bb.put((byte) (0xff & 255)); - - byteHeader = bb.array(); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, byteHeader); - } - - @Test - public void testDeserialize() throws Exception { - DHCP dhcp = deserializer.deserialize(byteHeader, 0, byteHeader.length); - - assertEquals(opCode, dhcp.opCode); - assertEquals(hardwareType, dhcp.hardwareType); - assertEquals(hardwareAddressLength, dhcp.hardwareAddressLength); - assertEquals(hops, dhcp.hops); - assertEquals(transactionId, dhcp.transactionId); - assertEquals(seconds, dhcp.seconds); - assertEquals(flags, dhcp.flags); - assertEquals(clientIpAddress, dhcp.clientIPAddress); - assertEquals(yourIpAddress, dhcp.yourIPAddress); - assertEquals(serverIpAddress, dhcp.serverIPAddress); - assertEquals(gatewayIpAddress, dhcp.gatewayIPAddress); - assertTrue(Arrays.equals(clientHardwareAddress, dhcp.clientHardwareAddress)); - - assertEquals(serverName, dhcp.serverName); - assertEquals(bootFileName, dhcp.bootFileName); - assertEquals(2, dhcp.options.size()); - assertEquals(hostNameOption, dhcp.options.get(0)); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/EthernetTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/EthernetTest.java deleted file mode 100644 index 15a01fc3..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/EthernetTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; - -import java.nio.ByteBuffer; - -import static org.junit.Assert.assertEquals; - -/** - * Unit tests for the Ethernet class. - */ -public class EthernetTest { - - private MacAddress dstMac; - private MacAddress srcMac; - private short ethertype = 6; - private short vlan = 5; - - private Deserializer<Ethernet> deserializer; - - private byte[] byteHeader; - private byte[] vlanByteHeader; - - @Before - public void setUp() { - deserializer = Ethernet.deserializer(); - - byte[] dstMacBytes = { - (byte) 0x88, (byte) 0x88, (byte) 0x88, (byte) 0x88, (byte) 0x88, - (byte) 0x88 }; - dstMac = MacAddress.valueOf(dstMacBytes); - byte[] srcMacBytes = { - (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, (byte) 0xaa, - (byte) 0xaa }; - srcMac = MacAddress.valueOf(srcMacBytes); - - // Create Ethernet byte array with no VLAN header - ByteBuffer bb = ByteBuffer.allocate(Ethernet.ETHERNET_HEADER_LENGTH); - bb.put(dstMacBytes); - bb.put(srcMacBytes); - bb.putShort(ethertype); - - byteHeader = bb.array(); - - // Create Ethernet byte array with a VLAN header - bb = ByteBuffer.allocate(Ethernet.ETHERNET_HEADER_LENGTH + Ethernet.VLAN_HEADER_LENGTH); - bb.put(dstMacBytes); - bb.put(srcMacBytes); - bb.putShort(Ethernet.TYPE_VLAN); - bb.putShort(vlan); - bb.putShort(ethertype); - - vlanByteHeader = bb.array(); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws DeserializationException { - PacketTestUtils.testDeserializeTruncated(deserializer, vlanByteHeader); - } - - @Test - public void testDeserializeNoVlan() throws Exception { - Ethernet eth = deserializer.deserialize(byteHeader, 0, byteHeader.length); - - assertEquals(dstMac, eth.getDestinationMAC()); - assertEquals(srcMac, eth.getSourceMAC()); - assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID()); - assertEquals(ethertype, eth.getEtherType()); - } - - @Test - public void testDeserializeWithVlan() throws Exception { - Ethernet eth = deserializer.deserialize(vlanByteHeader, 0, vlanByteHeader.length); - - assertEquals(dstMac, eth.getDestinationMAC()); - assertEquals(srcMac, eth.getSourceMAC()); - assertEquals(vlan, eth.getVlanID()); - assertEquals(ethertype, eth.getEtherType()); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ICMP6Test.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ICMP6Test.java deleted file mode 100644 index 39ddc24c..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ICMP6Test.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link ICMP6}. - */ -public class ICMP6Test { - private static final byte[] IPV6_SOURCE_ADDRESS = { - (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 - }; - private static final byte[] IPV6_DESTINATION_ADDRESS = { - (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02 - }; - - private static IPv6 ipv6 = new IPv6(); - private static byte[] bytePacket = { - ICMP6.ECHO_REQUEST, // type - (byte) 0x00, // code - (byte) 0x82, (byte) 0xbc, // checksum - }; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - ipv6.setSourceAddress(IPV6_SOURCE_ADDRESS); - ipv6.setDestinationAddress(IPV6_DESTINATION_ADDRESS); - ipv6.setNextHeader(IPv6.PROTOCOL_ICMP6); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - ICMP6 icmp6 = new ICMP6(); - icmp6.setIcmpType(ICMP6.ECHO_REQUEST); - icmp6.setIcmpCode((byte) 0); - icmp6.setParent(ipv6); - - assertArrayEquals(bytePacket, icmp6.serialize()); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(ICMP6.deserializer()); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(ICMP6.deserializer(), bytePacket); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws Exception { - ICMP6 icmp6 = ICMP6.deserializer().deserialize(bytePacket, 0, bytePacket.length); - - assertThat(icmp6.getIcmpType(), is(ICMP6.ECHO_REQUEST)); - assertThat(icmp6.getIcmpCode(), is((byte) 0x00)); - assertThat(icmp6.getChecksum(), is((short) 0x82bc)); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - ICMP6 icmp61 = new ICMP6(); - icmp61.setIcmpType(ICMP6.ECHO_REQUEST); - icmp61.setIcmpCode((byte) 0); - icmp61.setChecksum((short) 0); - - ICMP6 icmp62 = new ICMP6(); - icmp62.setIcmpType(ICMP6.ECHO_REPLY); - icmp62.setIcmpCode((byte) 0); - icmp62.setChecksum((short) 0); - - assertTrue(icmp61.equals(icmp61)); - assertFalse(icmp61.equals(icmp62)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ICMPTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ICMPTest.java deleted file mode 100644 index 8514aa59..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ICMPTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; - -import java.nio.ByteBuffer; - -import static org.junit.Assert.assertEquals; - -/** - * Unit tests for the ICMP class. - */ -public class ICMPTest { - - private Deserializer<ICMP> deserializer; - - private byte icmpType = ICMP.TYPE_ECHO_REQUEST; - private byte icmpCode = 4; - private short checksum = 870; - - private byte[] headerBytes; - - @Before - public void setUp() throws Exception { - deserializer = ICMP.deserializer(); - - ByteBuffer bb = ByteBuffer.allocate(ICMP.ICMP_HEADER_LENGTH); - - bb.put(icmpType); - bb.put(icmpCode); - bb.putShort(checksum); - - headerBytes = bb.array(); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, headerBytes); - } - - @Test - public void testDeserialize() throws Exception { - ICMP icmp = deserializer.deserialize(headerBytes, 0, headerBytes.length); - - assertEquals(icmpType, icmp.getIcmpType()); - assertEquals(icmpCode, icmp.getIcmpCode()); - assertEquals(checksum, icmp.getChecksum()); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IGMPTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IGMPTest.java deleted file mode 100644 index a25f7217..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IGMPTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; - -import static junit.framework.Assert.assertTrue; - -/** - * Unit tests for IGMP class. - */ -public class IGMPTest { - private Deserializer<IGMP> deserializer; - - private IGMP igmpQuery; - private IGMP igmpMembership; - - private Ip4Address gaddr1; - private Ip4Address gaddr2; - private Ip4Address saddr1; - private Ip4Address saddr2; - - @Before - public void setUp() throws Exception { - gaddr1 = Ip4Address.valueOf(0xe1010101); - gaddr2 = Ip4Address.valueOf(0xe2020202); - saddr1 = Ip4Address.valueOf(0x0a010101); - saddr2 = Ip4Address.valueOf(0x0b020202); - - deserializer = IGMP.deserializer(); - - // Create an IGMP Query object - igmpQuery = new IGMP(); - igmpQuery.setIgmpType(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY); - igmpQuery.setMaxRespCode((byte) 0x7f); - IGMPQuery q = new IGMPQuery(gaddr1, (byte) 0x7f); - q.addSource(saddr1); - q.addSource(saddr2); - q.setSbit(false); - igmpQuery.groups.add(q); - - // Create an IGMP Membership Object - igmpMembership = new IGMP(); - igmpMembership.setIgmpType(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT); - IGMPMembership g1 = new IGMPMembership(gaddr1); - g1.addSource(saddr1); - g1.addSource(saddr2); - igmpMembership.groups.add(g1); - IGMPMembership g2 = new IGMPMembership(gaddr2); - g2.addSource(saddr1); - g2.addSource(saddr2); - igmpMembership.groups.add(g2); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - byte [] bits = igmpQuery.serialize(); - PacketTestUtils.testDeserializeTruncated(deserializer, bits); - - bits = igmpMembership.serialize(); - PacketTestUtils.testDeserializeTruncated(deserializer, bits); - } - - @Test - public void testDeserializeQuery() throws Exception { - byte [] data = igmpQuery.serialize(); - IGMP igmp = deserializer.deserialize(data, 0, data.length); - assertTrue(igmp.equals(igmpQuery)); - } - - @Test - public void testDeserializeMembership() throws Exception { - byte [] data = igmpMembership.serialize(); - IGMP igmp = deserializer.deserialize(data, 0, data.length); - assertTrue(igmp.equals(igmpMembership)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IPv4Test.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IPv4Test.java deleted file mode 100644 index 1bacf2a2..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IPv4Test.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; - -import java.nio.ByteBuffer; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Unit tests for IPv4 class. - */ -public class IPv4Test { - - private Deserializer<IPv4> deserializer; - - private byte version = 4; - private byte headerLength = 6; - private byte diffServ = 2; - private short totalLength = 20; - private short identification = 1; - private byte flags = 1; - private short fragmentOffset = 1; - private byte ttl = 60; - private byte protocol = 4; - private short checksum = 4; - private int sourceAddress = 1; - private int destinationAddress = 2; - private byte[] options = new byte[] {0x1, 0x2, 0x3, 0x4}; - - private byte[] headerBytes; - - @Before - public void setUp() throws Exception { - deserializer = IPv4.deserializer(); - - ByteBuffer bb = ByteBuffer.allocate(headerLength * 4); - - bb.put((byte) ((version & 0xf) << 4 | headerLength & 0xf)); - bb.put(diffServ); - bb.putShort(totalLength); - bb.putShort(identification); - bb.putShort((short) ((flags & 0x7) << 13 | fragmentOffset & 0x1fff)); - bb.put(ttl); - bb.put(protocol); - bb.putShort(checksum); - bb.putInt(sourceAddress); - bb.putInt(destinationAddress); - bb.put(options); - - headerBytes = bb.array(); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, headerBytes); - } - - @Test - public void testDeserialize() throws Exception { - IPv4 ipv4 = deserializer.deserialize(headerBytes, 0, headerBytes.length); - - assertEquals(version, ipv4.getVersion()); - assertEquals(headerLength, ipv4.getHeaderLength()); - assertEquals(diffServ, ipv4.getDiffServ()); - assertEquals(totalLength, ipv4.getTotalLength()); - assertEquals(identification, ipv4.getIdentification()); - assertEquals(flags, ipv4.getFlags()); - assertEquals(fragmentOffset, ipv4.getFragmentOffset()); - assertEquals(ttl, ipv4.getTtl()); - assertEquals(protocol, ipv4.getProtocol()); - assertEquals(checksum, ipv4.getChecksum()); - assertEquals(sourceAddress, ipv4.getSourceAddress()); - assertEquals(destinationAddress, ipv4.getDestinationAddress()); - assertTrue(ipv4.isTruncated()); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IPv6Test.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IPv6Test.java deleted file mode 100644 index 720a4d20..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IPv6Test.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.nio.ByteBuffer; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link IPv6}. - */ -public class IPv6Test { - private static final byte[] SOURCE_ADDRESS = { - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce - }; - private static final byte[] DESTINATION_ADDRESS = { - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xe6, (byte) 0xce, (byte) 0x8f, (byte) 0xff, (byte) 0xfe, (byte) 0x54, (byte) 0x37, (byte) 0xc8 - }; - private static Data data; - private static UDP udp; - private static byte[] bytePacket; - - private Deserializer<IPv6> deserializer; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - data = new Data(); - data.setData("testSerialize".getBytes()); - udp = new UDP(); - udp.setPayload(data); - - byte[] bytePayload = udp.serialize(); - byte[] byteHeader = { - (byte) 0x69, (byte) 0x31, (byte) 0x35, (byte) 0x79, - (byte) (bytePayload.length >> 8 & 0xff), (byte) (bytePayload.length & 0xff), - (byte) 0x11, (byte) 0x20, - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce, - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xe6, (byte) 0xce, (byte) 0x8f, (byte) 0xff, (byte) 0xfe, (byte) 0x54, (byte) 0x37, (byte) 0xc8, - }; - bytePacket = new byte[byteHeader.length + bytePayload.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); - } - - @Before - public void setUp() { - deserializer = IPv6.deserializer(); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - IPv6 ipv6 = new IPv6(); - ipv6.setPayload(udp); - ipv6.setVersion((byte) 6); - ipv6.setTrafficClass((byte) 0x93); - ipv6.setFlowLabel(0x13579); - ipv6.setNextHeader(IPv6.PROTOCOL_UDP); - ipv6.setHopLimit((byte) 32); - ipv6.setSourceAddress(SOURCE_ADDRESS); - ipv6.setDestinationAddress(DESTINATION_ADDRESS); - - assertArrayEquals(ipv6.serialize(), bytePacket); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - // Run the truncation test only on the IPv6 header - byte[] ipv6Header = new byte[IPv6.FIXED_HEADER_LENGTH]; - ByteBuffer.wrap(bytePacket).get(ipv6Header); - - PacketTestUtils.testDeserializeTruncated(deserializer, ipv6Header); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws DeserializationException { - IPv6 ipv6 = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertThat(ipv6.getVersion(), is((byte) 6)); - assertThat(ipv6.getTrafficClass(), is((byte) 0x93)); - assertThat(ipv6.getFlowLabel(), is(0x13579)); - assertThat(ipv6.getNextHeader(), is(IPv6.PROTOCOL_UDP)); - assertThat(ipv6.getHopLimit(), is((byte) 32)); - assertArrayEquals(ipv6.getSourceAddress(), SOURCE_ADDRESS); - assertArrayEquals(ipv6.getDestinationAddress(), DESTINATION_ADDRESS); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - IPv6 packet1 = new IPv6(); - packet1.setPayload(udp); - packet1.setVersion((byte) 6); - packet1.setTrafficClass((byte) 0x93); - packet1.setFlowLabel(0x13579); - packet1.setNextHeader(IPv6.PROTOCOL_UDP); - packet1.setHopLimit((byte) 32); - packet1.setSourceAddress(SOURCE_ADDRESS); - packet1.setDestinationAddress(DESTINATION_ADDRESS); - - IPv6 packet2 = new IPv6(); - packet2.setPayload(udp); - packet2.setVersion((byte) 6); - packet2.setTrafficClass((byte) 0x93); - packet2.setFlowLabel(0x13579); - packet2.setNextHeader(IPv6.PROTOCOL_UDP); - packet2.setHopLimit((byte) 32); - packet2.setSourceAddress(DESTINATION_ADDRESS); - packet2.setDestinationAddress(SOURCE_ADDRESS); - - assertTrue(packet1.equals(packet1)); - assertFalse(packet1.equals(packet2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip4AddressTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip4AddressTest.java deleted file mode 100644 index 3bbf0009..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip4AddressTest.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import com.google.common.net.InetAddresses; -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import java.net.InetAddress; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; - -/** - * Tests for class {@link Ip4Address}. - */ -public class Ip4AddressTest { - /** - * Tests the immutability of {@link Ip4Address}. - */ - @Test - public void testImmutable() { - assertThatClassIsImmutable(Ip4Address.class); - } - - /** - * Tests the IPv4 address version constant. - */ - @Test - public void testAddressVersion() { - assertThat(Ip4Address.VERSION, is(IpAddress.Version.INET)); - } - - /** - * Tests the length of the address in bytes (octets). - */ - @Test - public void testAddrByteLength() { - assertThat(Ip4Address.BYTE_LENGTH, is(4)); - } - - /** - * Tests the length of the address in bits. - */ - @Test - public void testAddrBitLength() { - assertThat(Ip4Address.BIT_LENGTH, is(32)); - } - - /** - * Tests returning the IP address version. - */ - @Test - public void testVersion() { - Ip4Address ipAddress; - - // IPv4 - ipAddress = Ip4Address.valueOf("0.0.0.0"); - assertThat(ipAddress.version(), is(IpAddress.Version.INET)); - } - - /** - * Tests returning an IPv4 address as a byte array. - */ - @Test - public void testAddressToOctetsIPv4() { - Ip4Address ipAddress; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipAddress = Ip4Address.valueOf("1.2.3.4"); - assertThat(ipAddress.toOctets(), is(value)); - - value = new byte[] {0, 0, 0, 0}; - ipAddress = Ip4Address.valueOf("0.0.0.0"); - assertThat(ipAddress.toOctets(), is(value)); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipAddress = Ip4Address.valueOf("255.255.255.255"); - assertThat(ipAddress.toOctets(), is(value)); - } - - /** - * Tests returning an IPv4 address as an integer. - */ - @Test - public void testToInt() { - Ip4Address ipAddress; - - ipAddress = Ip4Address.valueOf("1.2.3.4"); - assertThat(ipAddress.toInt(), is(0x01020304)); - - ipAddress = Ip4Address.valueOf("0.0.0.0"); - assertThat(ipAddress.toInt(), is(0)); - - ipAddress = Ip4Address.valueOf("255.255.255.255"); - assertThat(ipAddress.toInt(), is(-1)); - } - - /** - * Tests valueOf() converter for IPv4 integer value. - */ - @Test - public void testValueOfForIntegerIPv4() { - Ip4Address ipAddress; - - ipAddress = Ip4Address.valueOf(0x01020304); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - ipAddress = Ip4Address.valueOf(0); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - ipAddress = Ip4Address.valueOf(0xffffffff); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests valueOf() converter for IPv4 byte array. - */ - @Test - public void testValueOfByteArrayIPv4() { - Ip4Address ipAddress; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipAddress = Ip4Address.valueOf(value); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - value = new byte[] {0, 0, 0, 0}; - ipAddress = Ip4Address.valueOf(value); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipAddress = Ip4Address.valueOf(value); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests invalid valueOf() converter for a null array for IPv4. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullArrayIPv4() { - Ip4Address ipAddress; - byte[] value; - - value = null; - ipAddress = Ip4Address.valueOf(value); - } - - /** - * Tests invalid valueOf() converger for an array that is too short for - * IPv4. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfShortArrayIPv4() { - Ip4Address ipAddress; - byte[] value; - - value = new byte[] {1, 2, 3}; - ipAddress = Ip4Address.valueOf(value); - } - - /** - * Tests valueOf() converter for IPv4 byte array and an offset. - */ - @Test - public void testValueOfByteArrayOffsetIPv4() { - Ip4Address ipAddress; - byte[] value; - - value = new byte[] {11, 22, 33, // Preamble - 1, 2, 3, 4, - 44, 55}; // Extra bytes - ipAddress = Ip4Address.valueOf(value, 3); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - value = new byte[] {11, 22, // Preamble - 0, 0, 0, 0, - 33}; // Extra bytes - ipAddress = Ip4Address.valueOf(value, 2); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - value = new byte[] {11, 22, // Preamble - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - 33}; // Extra bytes - ipAddress = Ip4Address.valueOf(value, 2); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests invalid valueOf() converger for an array and an invalid offset - * for IPv4. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfArrayInvalidOffsetIPv4() { - Ip4Address ipAddress; - byte[] value; - - value = new byte[] {11, 22, 33, // Preamble - 1, 2, 3, 4, - 44, 55}; // Extra bytes - ipAddress = Ip4Address.valueOf(value, 6); - } - - /** - * Tests valueOf() converter for IPv4 InetAddress. - */ - @Test - public void testValueOfInetAddressIPv4() { - Ip4Address ipAddress; - InetAddress inetAddress; - - inetAddress = InetAddresses.forString("1.2.3.4"); - ipAddress = Ip4Address.valueOf(inetAddress); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - inetAddress = InetAddresses.forString("0.0.0.0"); - ipAddress = Ip4Address.valueOf(inetAddress); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - inetAddress = InetAddresses.forString("255.255.255.255"); - ipAddress = Ip4Address.valueOf(inetAddress); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests valueOf() converter for IPv4 string. - */ - @Test - public void testValueOfStringIPv4() { - Ip4Address ipAddress; - - ipAddress = Ip4Address.valueOf("1.2.3.4"); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - ipAddress = Ip4Address.valueOf("0.0.0.0"); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - ipAddress = Ip4Address.valueOf("255.255.255.255"); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests invalid valueOf() converter for a null string. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullString() { - Ip4Address ipAddress; - - String fromString = null; - ipAddress = Ip4Address.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an empty string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfEmptyString() { - Ip4Address ipAddress; - - String fromString = ""; - ipAddress = Ip4Address.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an incorrect string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIncorrectString() { - Ip4Address ipAddress; - - String fromString = "NoSuchIpAddress"; - ipAddress = Ip4Address.valueOf(fromString); - } - - /** - * Tests making a mask prefix for a given prefix length for IPv4. - */ - @Test - public void testMakeMaskPrefixIPv4() { - Ip4Address ipAddress; - - ipAddress = Ip4Address.makeMaskPrefix(25); - assertThat(ipAddress.toString(), is("255.255.255.128")); - - ipAddress = Ip4Address.makeMaskPrefix(0); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - ipAddress = Ip4Address.makeMaskPrefix(32); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests making a mask prefix for an invalid prefix length for IPv4: - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeNegativeMaskPrefixIPv4() { - Ip4Address ipAddress; - - ipAddress = Ip4Address.makeMaskPrefix(-1); - } - - /** - * Tests making a mask prefix for an invalid prefix length for IPv4: - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeTooLongMaskPrefixIPv4() { - Ip4Address ipAddress; - - ipAddress = Ip4Address.makeMaskPrefix(33); - } - - /** - * Tests making of a masked address for IPv4. - */ - @Test - public void testMakeMaskedAddressIPv4() { - Ip4Address ipAddress = Ip4Address.valueOf("1.2.3.5"); - Ip4Address ipAddressMasked; - - ipAddressMasked = Ip4Address.makeMaskedAddress(ipAddress, 24); - assertThat(ipAddressMasked.toString(), is("1.2.3.0")); - - ipAddressMasked = Ip4Address.makeMaskedAddress(ipAddress, 0); - assertThat(ipAddressMasked.toString(), is("0.0.0.0")); - - ipAddressMasked = Ip4Address.makeMaskedAddress(ipAddress, 32); - assertThat(ipAddressMasked.toString(), is("1.2.3.5")); - } - - /** - * Tests making of a masked address for invalid prefix length for IPv4: - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeNegativeMaskedAddressIPv4() { - Ip4Address ipAddress = Ip4Address.valueOf("1.2.3.5"); - Ip4Address ipAddressMasked; - - ipAddressMasked = Ip4Address.makeMaskedAddress(ipAddress, -1); - } - - /** - * Tests making of a masked address for an invalid prefix length for IPv4: - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeTooLongMaskedAddressIPv4() { - Ip4Address ipAddress = Ip4Address.valueOf("1.2.3.5"); - Ip4Address ipAddressMasked; - - ipAddressMasked = Ip4Address.makeMaskedAddress(ipAddress, 33); - } - - /** - * Tests comparison of {@link Ip4Address} for IPv4. - */ - @Test - public void testComparisonIPv4() { - Ip4Address addr1, addr2, addr3, addr4; - - addr1 = Ip4Address.valueOf("1.2.3.4"); - addr2 = Ip4Address.valueOf("1.2.3.4"); - addr3 = Ip4Address.valueOf("1.2.3.3"); - addr4 = Ip4Address.valueOf("1.2.3.5"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - - addr1 = Ip4Address.valueOf("255.2.3.4"); - addr2 = Ip4Address.valueOf("255.2.3.4"); - addr3 = Ip4Address.valueOf("255.2.3.3"); - addr4 = Ip4Address.valueOf("255.2.3.5"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - } - - /** - * Tests equality of {@link Ip4Address} for IPv4. - */ - @Test - public void testEqualityIPv4() { - new EqualsTester() - .addEqualityGroup(Ip4Address.valueOf("1.2.3.4"), - Ip4Address.valueOf("1.2.3.4")) - .addEqualityGroup(Ip4Address.valueOf("1.2.3.5"), - Ip4Address.valueOf("1.2.3.5")) - .addEqualityGroup(Ip4Address.valueOf("0.0.0.0"), - Ip4Address.valueOf("0.0.0.0")) - .addEqualityGroup(Ip4Address.valueOf("255.255.255.255"), - Ip4Address.valueOf("255.255.255.255")) - .testEquals(); - } - - /** - * Tests object string representation for IPv4. - */ - @Test - public void testToStringIPv4() { - Ip4Address ipAddress; - - ipAddress = Ip4Address.valueOf("1.2.3.4"); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - ipAddress = Ip4Address.valueOf("0.0.0.0"); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - ipAddress = Ip4Address.valueOf("255.255.255.255"); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip4PrefixTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip4PrefixTest.java deleted file mode 100644 index c731ed66..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip4PrefixTest.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; - -/** - * Tests for class {@link Ip4Prefix}. - */ -public class Ip4PrefixTest { - /** - * Tests the immutability of {@link Ip4Prefix}. - */ - @Test - public void testImmutable() { - assertThatClassIsImmutable(Ip4Prefix.class); - } - - /** - * Tests the IPv4 prefix address version constant. - */ - @Test - public void testAddressVersion() { - assertThat(Ip4Prefix.VERSION, is(IpAddress.Version.INET)); - } - - /** - * Tests the maximum mask length. - */ - @Test - public void testMaxMaskLength() { - assertThat(Ip4Prefix.MAX_MASK_LENGTH, is(32)); - } - - /** - * Tests returning the IP version of the prefix. - */ - @Test - public void testVersion() { - Ip4Prefix ipPrefix; - - // IPv4 - ipPrefix = Ip4Prefix.valueOf("0.0.0.0/0"); - assertThat(ipPrefix.version(), is(IpAddress.Version.INET)); - } - - /** - * Tests returning the IP address value and IP address prefix length of - * an IPv4 prefix. - */ - @Test - public void testAddressAndPrefixLengthIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf("1.2.3.0/24"); - assertThat(ipPrefix.address(), equalTo(Ip4Address.valueOf("1.2.3.0"))); - assertThat(ipPrefix.prefixLength(), is(24)); - - ipPrefix = Ip4Prefix.valueOf("1.2.3.4/24"); - assertThat(ipPrefix.address(), equalTo(Ip4Address.valueOf("1.2.3.0"))); - assertThat(ipPrefix.prefixLength(), is(24)); - - ipPrefix = Ip4Prefix.valueOf("1.2.3.4/32"); - assertThat(ipPrefix.address(), equalTo(Ip4Address.valueOf("1.2.3.4"))); - assertThat(ipPrefix.prefixLength(), is(32)); - - ipPrefix = Ip4Prefix.valueOf("1.2.3.5/32"); - assertThat(ipPrefix.address(), equalTo(Ip4Address.valueOf("1.2.3.5"))); - assertThat(ipPrefix.prefixLength(), is(32)); - - ipPrefix = Ip4Prefix.valueOf("0.0.0.0/0"); - assertThat(ipPrefix.address(), equalTo(Ip4Address.valueOf("0.0.0.0"))); - assertThat(ipPrefix.prefixLength(), is(0)); - - ipPrefix = Ip4Prefix.valueOf("255.255.255.255/32"); - assertThat(ipPrefix.address(), - equalTo(Ip4Address.valueOf("255.255.255.255"))); - assertThat(ipPrefix.prefixLength(), is(32)); - } - - /** - * Tests valueOf() converter for IPv4 integer value. - */ - @Test - public void testValueOfForIntegerIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf(0x01020304, 24); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = Ip4Prefix.valueOf(0x01020304, 32); - assertThat(ipPrefix.toString(), is("1.2.3.4/32")); - - ipPrefix = Ip4Prefix.valueOf(0x01020305, 32); - assertThat(ipPrefix.toString(), is("1.2.3.5/32")); - - ipPrefix = Ip4Prefix.valueOf(0, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf(0, 32); - assertThat(ipPrefix.toString(), is("0.0.0.0/32")); - - ipPrefix = Ip4Prefix.valueOf(0xffffffff, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf(0xffffffff, 16); - assertThat(ipPrefix.toString(), is("255.255.0.0/16")); - - ipPrefix = Ip4Prefix.valueOf(0xffffffff, 32); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests invalid valueOf() converter for IPv4 integer value and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIntegerNegativePrefixLengthIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf(0x01020304, -1); - } - - /** - * Tests invalid valueOf() converter for IPv4 integer value and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIntegerTooLongPrefixLengthIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf(0x01020304, 33); - } - - /** - * Tests valueOf() converter for IPv4 byte array. - */ - @Test - public void testValueOfByteArrayIPv4() { - Ip4Prefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipPrefix = Ip4Prefix.valueOf(value, 24); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = Ip4Prefix.valueOf(value, 32); - assertThat(ipPrefix.toString(), is("1.2.3.4/32")); - - value = new byte[] {1, 2, 3, 5}; - ipPrefix = Ip4Prefix.valueOf(value, 32); - assertThat(ipPrefix.toString(), is("1.2.3.5/32")); - - value = new byte[] {0, 0, 0, 0}; - ipPrefix = Ip4Prefix.valueOf(value, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf(value, 32); - assertThat(ipPrefix.toString(), is("0.0.0.0/32")); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipPrefix = Ip4Prefix.valueOf(value, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf(value, 16); - assertThat(ipPrefix.toString(), is("255.255.0.0/16")); - - ipPrefix = Ip4Prefix.valueOf(value, 32); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests invalid valueOf() converter for a null array for IPv4. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullArrayIPv4() { - Ip4Prefix ipPrefix; - byte[] value; - - value = null; - ipPrefix = Ip4Prefix.valueOf(value, 24); - } - - /** - * Tests invalid valueOf() converter for a short array for IPv4. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfShortArrayIPv4() { - Ip4Prefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3}; - ipPrefix = Ip4Prefix.valueOf(value, 24); - } - - /** - * Tests invalid valueOf() converter for IPv4 byte array and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfByteArrayNegativePrefixLengthIPv4() { - Ip4Prefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipPrefix = Ip4Prefix.valueOf(value, -1); - } - - /** - * Tests invalid valueOf() converter for IPv4 byte array and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfByteArrayTooLongPrefixLengthIPv4() { - Ip4Prefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipPrefix = Ip4Prefix.valueOf(value, 33); - } - - /** - * Tests valueOf() converter for IPv4 address. - */ - @Test - public void testValueOfAddressIPv4() { - Ip4Address ipAddress; - Ip4Prefix ipPrefix; - - ipAddress = Ip4Address.valueOf("1.2.3.4"); - ipPrefix = Ip4Prefix.valueOf(ipAddress, 24); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = Ip4Prefix.valueOf(ipAddress, 32); - assertThat(ipPrefix.toString(), is("1.2.3.4/32")); - - ipAddress = Ip4Address.valueOf("1.2.3.5"); - ipPrefix = Ip4Prefix.valueOf(ipAddress, 32); - assertThat(ipPrefix.toString(), is("1.2.3.5/32")); - - ipAddress = Ip4Address.valueOf("0.0.0.0"); - ipPrefix = Ip4Prefix.valueOf(ipAddress, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf(ipAddress, 32); - assertThat(ipPrefix.toString(), is("0.0.0.0/32")); - - ipAddress = Ip4Address.valueOf("255.255.255.255"); - ipPrefix = Ip4Prefix.valueOf(ipAddress, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf(ipAddress, 16); - assertThat(ipPrefix.toString(), is("255.255.0.0/16")); - - ipPrefix = Ip4Prefix.valueOf(ipAddress, 32); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests invalid valueOf() converter for a null IP address. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullAddress() { - Ip4Address ipAddress; - Ip4Prefix ipPrefix; - - ipAddress = null; - ipPrefix = Ip4Prefix.valueOf(ipAddress, 24); - } - - /** - * Tests invalid valueOf() converter for IPv4 address and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfAddressNegativePrefixLengthIPv4() { - Ip4Address ipAddress; - Ip4Prefix ipPrefix; - - ipAddress = Ip4Address.valueOf("1.2.3.4"); - ipPrefix = Ip4Prefix.valueOf(ipAddress, -1); - } - - /** - * Tests invalid valueOf() converter for IPv4 address and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfAddressTooLongPrefixLengthIPv4() { - Ip4Address ipAddress; - Ip4Prefix ipPrefix; - - ipAddress = Ip4Address.valueOf("1.2.3.4"); - ipPrefix = Ip4Prefix.valueOf(ipAddress, 33); - } - - /** - * Tests valueOf() converter for IPv4 string. - */ - @Test - public void testValueOfStringIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf("1.2.3.4/24"); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = Ip4Prefix.valueOf("1.2.3.4/32"); - assertThat(ipPrefix.toString(), is("1.2.3.4/32")); - - ipPrefix = Ip4Prefix.valueOf("1.2.3.5/32"); - assertThat(ipPrefix.toString(), is("1.2.3.5/32")); - - ipPrefix = Ip4Prefix.valueOf("0.0.0.0/0"); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf("0.0.0.0/32"); - assertThat(ipPrefix.toString(), is("0.0.0.0/32")); - - ipPrefix = Ip4Prefix.valueOf("255.255.255.255/0"); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf("255.255.255.255/16"); - assertThat(ipPrefix.toString(), is("255.255.0.0/16")); - - ipPrefix = Ip4Prefix.valueOf("255.255.255.255/32"); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests invalid valueOf() converter for a null string. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullString() { - Ip4Prefix ipPrefix; - String fromString; - - fromString = null; - ipPrefix = Ip4Prefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an empty string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfEmptyString() { - Ip4Prefix ipPrefix; - String fromString; - - fromString = ""; - ipPrefix = Ip4Prefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an incorrect string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIncorrectString() { - Ip4Prefix ipPrefix; - String fromString; - - fromString = "NoSuchIpPrefix"; - ipPrefix = Ip4Prefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for IPv4 string and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfStringNegativePrefixLengthIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf("1.2.3.4/-1"); - } - - /** - * Tests invalid valueOf() converter for IPv4 string and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfStringTooLongPrefixLengthIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf("1.2.3.4/33"); - } - - /** - * Tests IP prefix contains another IP prefix for IPv4. - */ - @Test - public void testContainsIpPrefixIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf("1.2.0.0/24"); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/24"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/32"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.4/32"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/16"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.3.0.0/24"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("0.0.0.0/16"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("0.0.0.0/0"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("255.255.255.255/32"))); - - ipPrefix = Ip4Prefix.valueOf("1.2.0.0/32"); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/24"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/32"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.4/32"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/16"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.3.0.0/24"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("0.0.0.0/16"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("0.0.0.0/0"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("255.255.255.255/32"))); - - ipPrefix = Ip4Prefix.valueOf("0.0.0.0/0"); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/24"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/32"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.4/32"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/16"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("1.3.0.0/24"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("0.0.0.0/16"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("0.0.0.0/0"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("255.255.255.255/32"))); - - ipPrefix = Ip4Prefix.valueOf("255.255.255.255/32"); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/24"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/32"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.4/32"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.2.0.0/16"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("1.3.0.0/24"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("0.0.0.0/16"))); - assertFalse(ipPrefix.contains(Ip4Prefix.valueOf("0.0.0.0/0"))); - assertTrue(ipPrefix.contains(Ip4Prefix.valueOf("255.255.255.255/32"))); - } - - /** - * Tests IP prefix contains IP address for IPv4. - */ - @Test - public void testContainsIpAddressIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf("1.2.0.0/24"); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("1.2.0.0"))); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("1.2.0.4"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("1.3.0.0"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("0.0.0.0"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("255.255.255.255"))); - - ipPrefix = Ip4Prefix.valueOf("1.2.0.0/32"); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("1.2.0.0"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("1.2.0.4"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("1.3.0.0"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("0.0.0.0"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("255.255.255.255"))); - - ipPrefix = Ip4Prefix.valueOf("0.0.0.0/0"); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("1.2.0.0"))); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("1.2.0.4"))); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("1.3.0.0"))); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("0.0.0.0"))); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("255.255.255.255"))); - - ipPrefix = Ip4Prefix.valueOf("255.255.255.255/32"); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("1.2.0.0"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("1.2.0.4"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("1.3.0.0"))); - assertFalse(ipPrefix.contains(Ip4Address.valueOf("0.0.0.0"))); - assertTrue(ipPrefix.contains(Ip4Address.valueOf("255.255.255.255"))); - } - - /** - * Tests equality of {@link Ip4Prefix} for IPv4. - */ - @Test - public void testEqualityIPv4() { - new EqualsTester() - .addEqualityGroup(Ip4Prefix.valueOf("1.2.0.0/24"), - Ip4Prefix.valueOf("1.2.0.0/24"), - Ip4Prefix.valueOf("1.2.0.4/24")) - .addEqualityGroup(Ip4Prefix.valueOf("1.2.0.0/16"), - Ip4Prefix.valueOf("1.2.0.0/16")) - .addEqualityGroup(Ip4Prefix.valueOf("1.2.0.0/32"), - Ip4Prefix.valueOf("1.2.0.0/32")) - .addEqualityGroup(Ip4Prefix.valueOf("1.3.0.0/24"), - Ip4Prefix.valueOf("1.3.0.0/24")) - .addEqualityGroup(Ip4Prefix.valueOf("0.0.0.0/0"), - Ip4Prefix.valueOf("0.0.0.0/0")) - .addEqualityGroup(Ip4Prefix.valueOf("255.255.255.255/32"), - Ip4Prefix.valueOf("255.255.255.255/32")) - .testEquals(); - } - - /** - * Tests object string representation for IPv4. - */ - @Test - public void testToStringIPv4() { - Ip4Prefix ipPrefix; - - ipPrefix = Ip4Prefix.valueOf("1.2.3.0/24"); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = Ip4Prefix.valueOf("1.2.3.4/24"); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = Ip4Prefix.valueOf("0.0.0.0/0"); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = Ip4Prefix.valueOf("255.255.255.255/32"); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip6AddressTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip6AddressTest.java deleted file mode 100644 index e7d017d1..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip6AddressTest.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import com.google.common.net.InetAddresses; -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import java.net.InetAddress; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; - -/** - * Tests for class {@link Ip6Address}. - */ -public class Ip6AddressTest { - /** - * Tests the immutability of {@link Ip6Address}. - */ - @Test - public void testImmutable() { - assertThatClassIsImmutable(Ip6Address.class); - } - - /** - * Tests the IPv4 address version constant. - */ - @Test - public void testAddressVersion() { - assertThat(Ip6Address.VERSION, is(IpAddress.Version.INET6)); - } - - /** - * Tests the length of the address in bytes (octets). - */ - @Test - public void testAddrByteLength() { - assertThat(Ip6Address.BYTE_LENGTH, is(16)); - } - - /** - * Tests the length of the address in bits. - */ - @Test - public void testAddrBitLength() { - assertThat(Ip6Address.BIT_LENGTH, is(128)); - } - - /** - * Tests returning the IP address version. - */ - @Test - public void testVersion() { - IpAddress ipAddress; - - // IPv6 - ipAddress = IpAddress.valueOf("::"); - assertThat(ipAddress.version(), is(IpAddress.Version.INET6)); - } - - /** - * Tests returning an IPv6 address as a byte array. - */ - @Test - public void testAddressToOctetsIPv6() { - Ip6Address ipAddress; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, - (byte) 0x88, (byte) 0x88}; - ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - assertThat(ipAddress.toOctets(), is(value)); - - value = new byte[] {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - ipAddress = Ip6Address.valueOf("::"); - assertThat(ipAddress.toOctets(), is(value)); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipAddress = - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - assertThat(ipAddress.toOctets(), is(value)); - } - - /** - * Tests valueOf() converter for IPv6 byte array. - */ - @Test - public void testValueOfByteArrayIPv6() { - Ip6Address ipAddress; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, - (byte) 0x88, (byte) 0x88}; - ipAddress = Ip6Address.valueOf(value); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - value = new byte[] {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - ipAddress = Ip6Address.valueOf(value); - assertThat(ipAddress.toString(), is("::")); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipAddress = Ip6Address.valueOf(value); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } - - /** - * Tests invalid valueOf() converter for a null array for IPv6. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullArrayIPv6() { - Ip6Address ipAddress; - byte[] value; - - value = null; - ipAddress = Ip6Address.valueOf(value); - } - - /** - * Tests invalid valueOf() converger for an array that is too short for - * IPv6. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfShortArrayIPv6() { - Ip6Address ipAddress; - byte[] value; - - value = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}; - ipAddress = Ip6Address.valueOf(value); - } - - /** - * Tests valueOf() converter for IPv6 byte array and an offset. - */ - @Test - public void testValueOfByteArrayOffsetIPv6() { - Ip6Address ipAddress; - byte[] value; - - value = new byte[] {11, 22, 33, // Preamble - 0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, - (byte) 0x88, (byte) 0x88, - 44, 55}; // Extra bytes - ipAddress = Ip6Address.valueOf(value, 3); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - value = new byte[] {11, 22, // Preamble - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 33}; // Extra bytes - ipAddress = Ip6Address.valueOf(value, 2); - assertThat(ipAddress.toString(), is("::")); - - value = new byte[] {11, 22, // Preamble - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - 33}; // Extra bytes - ipAddress = Ip6Address.valueOf(value, 2); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } - - /** - * Tests invalid valueOf() converger for an array and an invalid offset - * for IPv6. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfArrayInvalidOffsetIPv6() { - Ip6Address ipAddress; - byte[] value; - - value = new byte[] {11, 22, 33, // Preamble - 0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, - (byte) 0x88, (byte) 0x88, - 44, 55}; // Extra bytes - ipAddress = Ip6Address.valueOf(value, 6); - } - - /** - * Tests valueOf() converter for IPv6 InetAddress. - */ - @Test - public void testValueOfInetAddressIPv6() { - Ip6Address ipAddress; - InetAddress inetAddress; - - inetAddress = - InetAddresses.forString("1111:2222:3333:4444:5555:6666:7777:8888"); - ipAddress = Ip6Address.valueOf(inetAddress); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - inetAddress = InetAddresses.forString("::"); - ipAddress = Ip6Address.valueOf(inetAddress); - assertThat(ipAddress.toString(), is("::")); - - inetAddress = - InetAddresses.forString("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - ipAddress = Ip6Address.valueOf(inetAddress); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } - - /** - * Tests valueOf() converter for IPv6 string. - */ - @Test - public void testValueOfStringIPv6() { - Ip6Address ipAddress; - - ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - ipAddress = Ip6Address.valueOf("::"); - assertThat(ipAddress.toString(), is("::")); - - ipAddress = - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } - - /** - * Tests invalid valueOf() converter for a null string. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullString() { - Ip6Address ipAddress; - - String fromString = null; - ipAddress = Ip6Address.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an empty string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfEmptyString() { - Ip6Address ipAddress; - - String fromString = ""; - ipAddress = Ip6Address.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an incorrect string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIncorrectString() { - Ip6Address ipAddress; - - String fromString = "NoSuchIpAddress"; - ipAddress = Ip6Address.valueOf(fromString); - } - - /** - * Tests making a mask prefix for a given prefix length for IPv6. - */ - @Test - public void testMakeMaskPrefixIPv6() { - Ip6Address ipAddress; - - ipAddress = Ip6Address.makeMaskPrefix(8); - assertThat(ipAddress.toString(), is("ff00::")); - - ipAddress = Ip6Address.makeMaskPrefix(120); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00")); - - ipAddress = Ip6Address.makeMaskPrefix(0); - assertThat(ipAddress.toString(), is("::")); - - ipAddress = Ip6Address.makeMaskPrefix(128); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - - ipAddress = Ip6Address.makeMaskPrefix(64); - assertThat(ipAddress.toString(), is("ffff:ffff:ffff:ffff::")); - } - - /** - * Tests making a mask prefix for an invalid prefix length for IPv6: - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeNegativeMaskPrefixIPv6() { - Ip6Address ipAddress; - - ipAddress = Ip6Address.makeMaskPrefix(-1); - } - - /** - * Tests making a mask prefix for an invalid prefix length for IPv6: - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeTooLongMaskPrefixIPv6() { - Ip6Address ipAddress; - - ipAddress = Ip6Address.makeMaskPrefix(129); - } - - /** - * Tests making of a masked address for IPv6. - */ - @Test - public void testMakeMaskedAddressIPv6() { - Ip6Address ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8885"); - Ip6Address ipAddressMasked; - - ipAddressMasked = Ip6Address.makeMaskedAddress(ipAddress, 8); - assertThat(ipAddressMasked.toString(), is("1100::")); - - ipAddressMasked = Ip6Address.makeMaskedAddress(ipAddress, 120); - assertThat(ipAddressMasked.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8800")); - - ipAddressMasked = Ip6Address.makeMaskedAddress(ipAddress, 0); - assertThat(ipAddressMasked.toString(), is("::")); - - ipAddressMasked = Ip6Address.makeMaskedAddress(ipAddress, 128); - assertThat(ipAddressMasked.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8885")); - - ipAddressMasked = Ip6Address.makeMaskedAddress(ipAddress, 64); - assertThat(ipAddressMasked.toString(), is("1111:2222:3333:4444::")); - } - - /** - * Tests making of a masked address for invalid prefix length for IPv6: - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeNegativeMaskedAddressIPv6() { - Ip6Address ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8885"); - Ip6Address ipAddressMasked; - - ipAddressMasked = Ip6Address.makeMaskedAddress(ipAddress, -1); - } - - /** - * Tests making of a masked address for an invalid prefix length for IPv6: - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeTooLongMaskedAddressIPv6() { - Ip6Address ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8885"); - Ip6Address ipAddressMasked; - - ipAddressMasked = Ip6Address.makeMaskedAddress(ipAddress, 129); - } - - /** - * Tests comparison of {@link Ip6Address} for IPv6. - */ - @Test - public void testComparisonIPv6() { - Ip6Address addr1, addr2, addr3, addr4; - - addr1 = Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - addr2 = Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - addr3 = Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8887"); - addr4 = Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8889"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - - addr1 = Ip6Address.valueOf("ffff:2222:3333:4444:5555:6666:7777:8888"); - addr2 = Ip6Address.valueOf("ffff:2222:3333:4444:5555:6666:7777:8888"); - addr3 = Ip6Address.valueOf("ffff:2222:3333:4444:5555:6666:7777:8887"); - addr4 = Ip6Address.valueOf("ffff:2222:3333:4444:5555:6666:7777:8889"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - - addr1 = Ip6Address.valueOf("ffff:2222:3333:4444:5555:6666:7777:8888"); - addr2 = Ip6Address.valueOf("ffff:2222:3333:4444:5555:6666:7777:8888"); - addr3 = Ip6Address.valueOf("ffff:2222:3333:4443:5555:6666:7777:8888"); - addr4 = Ip6Address.valueOf("ffff:2222:3333:4445:5555:6666:7777:8888"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - } - - /** - * Tests equality of {@link Ip6Address} for IPv6. - */ - @Test - public void testEqualityIPv6() { - new EqualsTester() - .addEqualityGroup( - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"), - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888")) - .addEqualityGroup( - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:888a"), - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:888a")) - .addEqualityGroup( - Ip6Address.valueOf("::"), - Ip6Address.valueOf("::")) - .addEqualityGroup( - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) - .testEquals(); - } - - /** - * Tests object string representation for IPv6. - */ - @Test - public void testToStringIPv6() { - Ip6Address ipAddress; - - ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - ipAddress = Ip6Address.valueOf("1111::8888"); - assertThat(ipAddress.toString(), is("1111::8888")); - - ipAddress = Ip6Address.valueOf("1111::"); - assertThat(ipAddress.toString(), is("1111::")); - - ipAddress = Ip6Address.valueOf("::8888"); - assertThat(ipAddress.toString(), is("::8888")); - - ipAddress = Ip6Address.valueOf("::"); - assertThat(ipAddress.toString(), is("::")); - - ipAddress = - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip6PrefixTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip6PrefixTest.java deleted file mode 100644 index dceeb840..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/Ip6PrefixTest.java +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; - -/** - * Tests for class {@link Ip6Prefix}. - */ -public class Ip6PrefixTest { - /** - * Tests the immutability of {@link Ip6Prefix}. - */ - @Test - public void testImmutable() { - assertThatClassIsImmutable(Ip6Prefix.class); - } - - /** - * Tests the IPv4 prefix address version constant. - */ - @Test - public void testAddressVersion() { - assertThat(Ip6Prefix.VERSION, is(IpAddress.Version.INET6)); - } - - /** - * Tests the maximum mask length. - */ - @Test - public void testMaxMaskLength() { - assertThat(Ip6Prefix.MAX_MASK_LENGTH, is(128)); - } - - /** - * Tests returning the IP version of the prefix. - */ - @Test - public void testVersion() { - Ip6Prefix ipPrefix; - - // IPv6 - ipPrefix = Ip6Prefix.valueOf("::/0"); - assertThat(ipPrefix.version(), is(IpAddress.Version.INET6)); - } - - /** - * Tests returning the IP address value and IP address prefix length of - * an IPv6 prefix. - */ - @Test - public void testAddressAndPrefixLengthIPv6() { - Ip6Prefix ipPrefix; - - ipPrefix = Ip6Prefix.valueOf("1100::/8"); - assertThat(ipPrefix.address(), equalTo(Ip6Address.valueOf("1100::"))); - assertThat(ipPrefix.prefixLength(), is(8)); - - ipPrefix = - Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/8"); - assertThat(ipPrefix.address(), equalTo(Ip6Address.valueOf("1100::"))); - assertThat(ipPrefix.prefixLength(), is(8)); - - ipPrefix = - Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8800/120"); - assertThat(ipPrefix.address(), - equalTo(Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8800"))); - assertThat(ipPrefix.prefixLength(), is(120)); - - ipPrefix = - Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/128"); - assertThat(ipPrefix.address(), - equalTo(Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8885"))); - assertThat(ipPrefix.prefixLength(), is(128)); - - ipPrefix = Ip6Prefix.valueOf("::/0"); - assertThat(ipPrefix.address(), equalTo(Ip6Address.valueOf("::"))); - assertThat(ipPrefix.prefixLength(), is(0)); - - ipPrefix = - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertThat(ipPrefix.address(), - equalTo(Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - assertThat(ipPrefix.prefixLength(), is(128)); - - ipPrefix = - Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/64"); - assertThat(ipPrefix.address(), - equalTo(Ip6Address.valueOf("1111:2222:3333:4444::"))); - assertThat(ipPrefix.prefixLength(), is(64)); - } - - /** - * Tests valueOf() converter for IPv6 byte array. - */ - @Test - public void testValueOfByteArrayIPv6() { - Ip6Prefix ipPrefix; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, (byte) 0x88, (byte) 0x88}; - ipPrefix = Ip6Prefix.valueOf(value, 120); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8800/120")); - - ipPrefix = Ip6Prefix.valueOf(value, 128); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888/128")); - - value = new byte[] {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - ipPrefix = Ip6Prefix.valueOf(value, 0); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = Ip6Prefix.valueOf(value, 128); - assertThat(ipPrefix.toString(), is("::/128")); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipPrefix = Ip6Prefix.valueOf(value, 0); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = Ip6Prefix.valueOf(value, 64); - assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64")); - - ipPrefix = Ip6Prefix.valueOf(value, 128); - assertThat(ipPrefix.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")); - } - - /** - * Tests invalid valueOf() converter for a null array for IPv6. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullArrayIPv6() { - Ip6Prefix ipPrefix; - byte[] value; - - value = null; - ipPrefix = Ip6Prefix.valueOf(value, 120); - } - - /** - * Tests invalid valueOf() converter for a short array for IPv6. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfShortArrayIPv6() { - Ip6Prefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}; - ipPrefix = Ip6Prefix.valueOf(value, 120); - } - - /** - * Tests invalid valueOf() converter for IPv6 byte array and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfByteArrayNegativePrefixLengthIPv6() { - Ip6Prefix ipPrefix; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, (byte) 0x88, (byte) 0x88}; - ipPrefix = Ip6Prefix.valueOf(value, -1); - } - - /** - * Tests invalid valueOf() converter for IPv6 byte array and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfByteArrayTooLongPrefixLengthIPv6() { - Ip6Prefix ipPrefix; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, (byte) 0x88, (byte) 0x88}; - ipPrefix = Ip6Prefix.valueOf(value, 129); - } - - /** - * Tests valueOf() converter for IPv6 address. - */ - @Test - public void testValueOfAddressIPv6() { - Ip6Address ipAddress; - Ip6Prefix ipPrefix; - - ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - ipPrefix = Ip6Prefix.valueOf(ipAddress, 120); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8800/120")); - - ipPrefix = Ip6Prefix.valueOf(ipAddress, 128); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888/128")); - - ipAddress = Ip6Address.valueOf("::"); - ipPrefix = Ip6Prefix.valueOf(ipAddress, 0); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = Ip6Prefix.valueOf(ipAddress, 128); - assertThat(ipPrefix.toString(), is("::/128")); - - ipAddress = - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - ipPrefix = Ip6Prefix.valueOf(ipAddress, 0); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = Ip6Prefix.valueOf(ipAddress, 64); - assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64")); - - ipPrefix = Ip6Prefix.valueOf(ipAddress, 128); - assertThat(ipPrefix.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")); - } - - /** - * Tests invalid valueOf() converter for a null IP address. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullAddress() { - Ip6Address ipAddress; - Ip6Prefix ipPrefix; - - ipAddress = null; - ipPrefix = Ip6Prefix.valueOf(ipAddress, 24); - } - - /** - * Tests invalid valueOf() converter for IPv6 address and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfAddressNegativePrefixLengthIPv6() { - Ip6Address ipAddress; - Ip6Prefix ipPrefix; - - ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - ipPrefix = Ip6Prefix.valueOf(ipAddress, -1); - } - - /** - * Tests invalid valueOf() converter for IPv6 address and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfAddressTooLongPrefixLengthIPv6() { - Ip6Address ipAddress; - Ip6Prefix ipPrefix; - - ipAddress = - Ip6Address.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - ipPrefix = Ip6Prefix.valueOf(ipAddress, 129); - } - - /** - * Tests valueOf() converter for IPv6 string. - */ - @Test - public void testValueOfStringIPv6() { - Ip6Prefix ipPrefix; - - ipPrefix = - Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/120"); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8800/120")); - - ipPrefix = - Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/128"); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888/128")); - - ipPrefix = Ip6Prefix.valueOf("::/0"); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = Ip6Prefix.valueOf("::/128"); - assertThat(ipPrefix.toString(), is("::/128")); - - ipPrefix = - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/0"); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"); - assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64")); - - ipPrefix = - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertThat(ipPrefix.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")); - } - - /** - * Tests invalid valueOf() converter for a null string. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullString() { - Ip6Prefix ipPrefix; - String fromString; - - fromString = null; - ipPrefix = Ip6Prefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an empty string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfEmptyString() { - Ip6Prefix ipPrefix; - String fromString; - - fromString = ""; - ipPrefix = Ip6Prefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an incorrect string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIncorrectString() { - Ip6Prefix ipPrefix; - String fromString; - - fromString = "NoSuchIpPrefix"; - ipPrefix = Ip6Prefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for IPv6 string and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfStringNegativePrefixLengthIPv6() { - Ip6Prefix ipPrefix; - - ipPrefix = - Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/-1"); - } - - /** - * Tests invalid valueOf() converter for IPv6 string and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfStringTooLongPrefixLengthIPv6() { - Ip6Prefix ipPrefix; - - ipPrefix = - Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/129"); - } - - /** - * Tests IP prefix contains another IP prefix for IPv6. - */ - @Test - public void testContainsIpPrefixIPv6() { - Ip6Prefix ipPrefix; - - ipPrefix = Ip6Prefix.valueOf("1111:2222:3333:4444::/120"); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/120"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/128"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::1/128"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/64"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4445::/120"))); - assertFalse(ipPrefix.contains(Ip6Prefix.valueOf("::/64"))); - assertFalse(ipPrefix.contains(Ip6Prefix.valueOf("::/0"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - - ipPrefix = Ip6Prefix.valueOf("1111:2222:3333:4444::/128"); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/120"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/128"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::1/128"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/64"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4445::/120"))); - assertFalse(ipPrefix.contains(Ip6Prefix.valueOf("::/64"))); - assertFalse(ipPrefix.contains(Ip6Prefix.valueOf("::/0"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - - ipPrefix = Ip6Prefix.valueOf("::/0"); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/120"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/128"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::1/128"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/64"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4445::/120"))); - assertTrue(ipPrefix.contains(Ip6Prefix.valueOf("::/64"))); - assertTrue(ipPrefix.contains(Ip6Prefix.valueOf("::/0"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - - ipPrefix = - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/120"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/128"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::1/128"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4444::/64"))); - assertFalse(ipPrefix.contains( - Ip6Prefix.valueOf("1111:2222:3333:4445::/120"))); - assertFalse(ipPrefix.contains(Ip6Prefix.valueOf("::/64"))); - assertFalse(ipPrefix.contains(Ip6Prefix.valueOf("::/0"))); - assertTrue(ipPrefix.contains( - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - } - - /** - * Tests IP prefix contains IP address for IPv6. - */ - @Test - public void testContainsIpAddressIPv6() { - Ip6Prefix ipPrefix; - - ipPrefix = Ip6Prefix.valueOf("1111:2222:3333:4444::/120"); - assertTrue(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4444::"))); - assertTrue(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4444::1"))); - assertFalse(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4445::"))); - assertFalse(ipPrefix.contains(Ip6Address.valueOf("::"))); - assertFalse(ipPrefix.contains( - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - - ipPrefix = Ip6Prefix.valueOf("1111:2222:3333:4444::/128"); - assertTrue(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4444::"))); - assertFalse(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4444::1"))); - assertFalse(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4445::"))); - assertFalse(ipPrefix.contains(Ip6Address.valueOf("::"))); - assertFalse(ipPrefix.contains( - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - - ipPrefix = Ip6Prefix.valueOf("::/0"); - assertTrue(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4444::"))); - assertTrue(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4444::1"))); - assertTrue(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4445::"))); - assertTrue(ipPrefix.contains(Ip6Address.valueOf("::"))); - assertTrue(ipPrefix.contains( - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - - ipPrefix = - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertFalse(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4444::"))); - assertFalse(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4444::1"))); - assertFalse(ipPrefix.contains( - Ip6Address.valueOf("1111:2222:3333:4445::"))); - assertFalse(ipPrefix.contains(Ip6Address.valueOf("::"))); - assertTrue(ipPrefix.contains( - Ip6Address.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - } - - /** - * Tests equality of {@link Ip6Prefix} for IPv6. - */ - @Test - public void testEqualityIPv6() { - new EqualsTester() - .addEqualityGroup( - Ip6Prefix.valueOf("1111:2222:3333:4444::/120"), - Ip6Prefix.valueOf("1111:2222:3333:4444::1/120"), - Ip6Prefix.valueOf("1111:2222:3333:4444::/120")) - .addEqualityGroup( - Ip6Prefix.valueOf("1111:2222:3333:4444::/64"), - Ip6Prefix.valueOf("1111:2222:3333:4444::/64")) - .addEqualityGroup( - Ip6Prefix.valueOf("1111:2222:3333:4444::/128"), - Ip6Prefix.valueOf("1111:2222:3333:4444::/128")) - .addEqualityGroup( - Ip6Prefix.valueOf("1111:2222:3333:4445::/64"), - Ip6Prefix.valueOf("1111:2222:3333:4445::/64")) - .addEqualityGroup( - Ip6Prefix.valueOf("::/0"), - Ip6Prefix.valueOf("::/0")) - .addEqualityGroup( - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"), - Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")) - .testEquals(); - } - - /** - * Tests object string representation for IPv6. - */ - @Test - public void testToStringIPv6() { - Ip6Prefix ipPrefix; - - ipPrefix = Ip6Prefix.valueOf("1100::/8"); - assertThat(ipPrefix.toString(), is("1100::/8")); - - ipPrefix = Ip6Prefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/8"); - assertThat(ipPrefix.toString(), is("1100::/8")); - - ipPrefix = Ip6Prefix.valueOf("::/0"); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = Ip6Prefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertThat(ipPrefix.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IpAddressTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IpAddressTest.java deleted file mode 100644 index 8618c466..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IpAddressTest.java +++ /dev/null @@ -1,946 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.net.InetAddress; - -import org.junit.Test; - -import com.google.common.net.InetAddresses; -import com.google.common.testing.EqualsTester; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; -import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; - -/** - * Tests for class {@link IpAddress}. - */ -public class IpAddressTest { - /** - * Tests the immutability of {@link IpAddress}. - */ - @Test - public void testImmutable() { - assertThatClassIsImmutableBaseClass(IpAddress.class); - } - - /** - * Tests the length of the address in bytes (octets). - */ - @Test - public void testAddrByteLength() { - assertThat(IpAddress.INET_BYTE_LENGTH, is(4)); - assertThat(IpAddress.INET6_BYTE_LENGTH, is(16)); - assertThat(IpAddress.byteLength(IpAddress.Version.INET), is(4)); - assertThat(IpAddress.byteLength(IpAddress.Version.INET6), is(16)); - } - - /** - * Tests the length of the address in bits. - */ - @Test - public void testAddrBitLength() { - assertThat(IpAddress.INET_BIT_LENGTH, is(32)); - assertThat(IpAddress.INET6_BIT_LENGTH, is(128)); - } - - /** - * Tests returning the IP address version. - */ - @Test - public void testVersion() { - IpAddress ipAddress; - - // IPv4 - ipAddress = IpAddress.valueOf("0.0.0.0"); - assertThat(ipAddress.version(), is(IpAddress.Version.INET)); - - // IPv6 - ipAddress = IpAddress.valueOf("::"); - assertThat(ipAddress.version(), is(IpAddress.Version.INET6)); - } - - /** - * Tests whether the IP version of an address is IPv4. - */ - @Test - public void testIsIp4() { - IpAddress ipAddress; - - // IPv4 - ipAddress = IpAddress.valueOf("0.0.0.0"); - assertTrue(ipAddress.isIp4()); - - // IPv6 - ipAddress = IpAddress.valueOf("::"); - assertFalse(ipAddress.isIp4()); - } - - /** - * Tests whether the IP version of an address is IPv6. - */ - @Test - public void testIsIp6() { - IpAddress ipAddress; - - // IPv4 - ipAddress = IpAddress.valueOf("0.0.0.0"); - assertFalse(ipAddress.isIp6()); - - // IPv6 - ipAddress = IpAddress.valueOf("::"); - assertTrue(ipAddress.isIp6()); - } - - /** - * Tests getting the Ip4Address and Ip6Address view of the IP address. - */ - @Test - public void testGetIp4AndIp6AddressView() { - IpAddress ipAddress; - Ip4Address ip4Address; - Ip6Address ip6Address; - - // Pure IPv4 IpAddress - ipAddress = IpAddress.valueOf("1.2.3.4"); - ip4Address = ipAddress.getIp4Address(); - ip6Address = ipAddress.getIp6Address(); - assertThat(ip4Address.toString(), is("1.2.3.4")); - assertNull(ip6Address); - - // IPv4 IpAddress that is Ip4Address - ipAddress = Ip4Address.valueOf("1.2.3.4"); - ip4Address = ipAddress.getIp4Address(); - ip6Address = ipAddress.getIp6Address(); - assertThat(ip4Address.toString(), is("1.2.3.4")); - assertNull(ip6Address); - - // Pure IPv6 IpAddress - ipAddress = IpAddress.valueOf("1111:2222::"); - ip4Address = ipAddress.getIp4Address(); - ip6Address = ipAddress.getIp6Address(); - assertNull(ip4Address); - assertThat(ip6Address.toString(), is("1111:2222::")); - - // IPv6 IpAddress that is Ip6Address - ipAddress = Ip6Address.valueOf("1111:2222::"); - ip4Address = ipAddress.getIp4Address(); - ip6Address = ipAddress.getIp6Address(); - assertNull(ip4Address); - assertThat(ip6Address.toString(), is("1111:2222::")); - } - - /** - * Tests returning an IPv4 address as a byte array. - */ - @Test - public void testAddressToOctetsIPv4() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipAddress = IpAddress.valueOf("1.2.3.4"); - assertThat(ipAddress.toOctets(), is(value)); - - value = new byte[] {0, 0, 0, 0}; - ipAddress = IpAddress.valueOf("0.0.0.0"); - assertThat(ipAddress.toOctets(), is(value)); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipAddress = IpAddress.valueOf("255.255.255.255"); - assertThat(ipAddress.toOctets(), is(value)); - } - - /** - * Tests returning an IPv6 address as a byte array. - */ - @Test - public void testAddressToOctetsIPv6() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, - (byte) 0x88, (byte) 0x88}; - ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - assertThat(ipAddress.toOctets(), is(value)); - - value = new byte[] {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - ipAddress = IpAddress.valueOf("::"); - assertThat(ipAddress.toOctets(), is(value)); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipAddress = - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - assertThat(ipAddress.toOctets(), is(value)); - } - - /** - * Tests valueOf() converter for IPv4 integer value. - */ - @Test - public void testValueOfForIntegerIPv4() { - IpAddress ipAddress; - - ipAddress = IpAddress.valueOf(0x01020304); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - ipAddress = IpAddress.valueOf(0); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - ipAddress = IpAddress.valueOf(0xffffffff); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests valueOf() converter for IPv4 byte array. - */ - @Test - public void testValueOfByteArrayIPv4() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - value = new byte[] {0, 0, 0, 0}; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests valueOf() converter for IPv6 byte array. - */ - @Test - public void testValueOfByteArrayIPv6() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, - (byte) 0x88, (byte) 0x88}; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - value = new byte[] {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value); - assertThat(ipAddress.toString(), is("::")); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } - - /** - * Tests invalid valueOf() converter for a null array for IPv4. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullArrayIPv4() { - IpAddress ipAddress; - byte[] value; - - value = null; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value); - } - - /** - * Tests invalid valueOf() converter for a null array for IPv6. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullArrayIPv6() { - IpAddress ipAddress; - byte[] value; - - value = null; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value); - } - - /** - * Tests invalid valueOf() converger for an array that is too short for - * IPv4. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfShortArrayIPv4() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {1, 2, 3}; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value); - } - - /** - * Tests invalid valueOf() converger for an array that is too short for - * IPv6. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfShortArrayIPv6() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}; - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value); - } - - /** - * Tests valueOf() converter for IPv4 byte array and an offset. - */ - @Test - public void testValueOfByteArrayOffsetIPv4() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {11, 22, 33, // Preamble - 1, 2, 3, 4, - 44, 55}; // Extra bytes - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value, 3); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - value = new byte[] {11, 22, // Preamble - 0, 0, 0, 0, - 33}; // Extra bytes - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value, 2); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - value = new byte[] {11, 22, // Preamble - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - 33}; // Extra bytes - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value, 2); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests valueOf() converter for IPv6 byte array and an offset. - */ - @Test - public void testValueOfByteArrayOffsetIPv6() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {11, 22, 33, // Preamble - 0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, - (byte) 0x88, (byte) 0x88, - 44, 55}; // Extra bytes - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value, 3); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - value = new byte[] {11, 22, // Preamble - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 33}; // Extra bytes - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value, 2); - assertThat(ipAddress.toString(), is("::")); - - value = new byte[] {11, 22, // Preamble - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - 33}; // Extra bytes - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value, 2); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } - - /** - * Tests invalid valueOf() converger for an array and an invalid offset - * for IPv4. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfArrayInvalidOffsetIPv4() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {11, 22, 33, // Preamble - 1, 2, 3, 4, - 44, 55}; // Extra bytes - ipAddress = IpAddress.valueOf(IpAddress.Version.INET, value, 6); - } - - /** - * Tests invalid valueOf() converger for an array and an invalid offset - * for IPv6. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfArrayInvalidOffsetIPv6() { - IpAddress ipAddress; - byte[] value; - - value = new byte[] {11, 22, 33, // Preamble - 0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, - (byte) 0x88, (byte) 0x88, - 44, 55}; // Extra bytes - ipAddress = IpAddress.valueOf(IpAddress.Version.INET6, value, 6); - } - - /** - * Tests valueOf() converter for IPv4 InetAddress. - */ - @Test - public void testValueOfInetAddressIPv4() { - IpAddress ipAddress; - InetAddress inetAddress; - - inetAddress = InetAddresses.forString("1.2.3.4"); - ipAddress = IpAddress.valueOf(inetAddress); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - inetAddress = InetAddresses.forString("0.0.0.0"); - ipAddress = IpAddress.valueOf(inetAddress); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - inetAddress = InetAddresses.forString("255.255.255.255"); - ipAddress = IpAddress.valueOf(inetAddress); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests valueOf() converter for IPv6 InetAddress. - */ - @Test - public void testValueOfInetAddressIPv6() { - IpAddress ipAddress; - InetAddress inetAddress; - - inetAddress = - InetAddresses.forString("1111:2222:3333:4444:5555:6666:7777:8888"); - ipAddress = IpAddress.valueOf(inetAddress); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - inetAddress = InetAddresses.forString("::"); - ipAddress = IpAddress.valueOf(inetAddress); - assertThat(ipAddress.toString(), is("::")); - - inetAddress = - InetAddresses.forString("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - ipAddress = IpAddress.valueOf(inetAddress); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } - - /** - * Tests valueOf() converter for IPv4 string. - */ - @Test - public void testValueOfStringIPv4() { - IpAddress ipAddress; - - ipAddress = IpAddress.valueOf("1.2.3.4"); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - ipAddress = IpAddress.valueOf("0.0.0.0"); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - ipAddress = IpAddress.valueOf("255.255.255.255"); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests valueOf() converter for IPv6 string. - */ - @Test - public void testValueOfStringIPv6() { - IpAddress ipAddress; - - ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - ipAddress = IpAddress.valueOf("::"); - assertThat(ipAddress.toString(), is("::")); - - ipAddress = - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - } - - /** - * Tests invalid valueOf() converter for a null string. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullString() { - IpAddress ipAddress; - - String fromString = null; - ipAddress = IpAddress.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an empty string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfEmptyString() { - IpAddress ipAddress; - - String fromString = ""; - ipAddress = IpAddress.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an incorrect string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIncorrectString() { - IpAddress ipAddress; - - String fromString = "NoSuchIpAddress"; - ipAddress = IpAddress.valueOf(fromString); - } - - /** - * Tests making a mask prefix for a given prefix length for IPv4. - */ - @Test - public void testMakeMaskPrefixIPv4() { - IpAddress ipAddress; - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET, 25); - assertThat(ipAddress.toString(), is("255.255.255.128")); - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET, 0); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET, 32); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests making a mask prefix for a given prefix length for IPv6. - */ - @Test - public void testMakeMaskPrefixIPv6() { - IpAddress ipAddress; - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET6, 8); - assertThat(ipAddress.toString(), is("ff00::")); - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET6, 120); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00")); - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET6, 0); - assertThat(ipAddress.toString(), is("::")); - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET6, 128); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET6, 64); - assertThat(ipAddress.toString(), is("ffff:ffff:ffff:ffff::")); - } - - /** - * Tests making a mask prefix for an invalid prefix length for IPv4: - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeNegativeMaskPrefixIPv4() { - IpAddress ipAddress; - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET, -1); - } - - /** - * Tests making a mask prefix for an invalid prefix length for IPv6: - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeNegativeMaskPrefixIPv6() { - IpAddress ipAddress; - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET6, -1); - } - - /** - * Tests making a mask prefix for an invalid prefix length for IPv4: - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeTooLongMaskPrefixIPv4() { - IpAddress ipAddress; - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET, 33); - } - - /** - * Tests making a mask prefix for an invalid prefix length for IPv6: - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeTooLongMaskPrefixIPv6() { - IpAddress ipAddress; - - ipAddress = IpAddress.makeMaskPrefix(IpAddress.Version.INET6, 129); - } - - /** - * Tests making of a masked address for IPv4. - */ - @Test - public void testMakeMaskedAddressIPv4() { - IpAddress ipAddress = IpAddress.valueOf("1.2.3.5"); - IpAddress ipAddressMasked; - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 24); - assertThat(ipAddressMasked.toString(), is("1.2.3.0")); - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 0); - assertThat(ipAddressMasked.toString(), is("0.0.0.0")); - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 32); - assertThat(ipAddressMasked.toString(), is("1.2.3.5")); - } - - /** - * Tests making of a masked address for IPv6. - */ - @Test - public void testMakeMaskedAddressIPv6() { - IpAddress ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8885"); - IpAddress ipAddressMasked; - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 8); - assertThat(ipAddressMasked.toString(), is("1100::")); - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 120); - assertThat(ipAddressMasked.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8800")); - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 0); - assertThat(ipAddressMasked.toString(), is("::")); - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 128); - assertThat(ipAddressMasked.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8885")); - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 64); - assertThat(ipAddressMasked.toString(), is("1111:2222:3333:4444::")); - } - - /** - * Tests making of a masked address for invalid prefix length for IPv4: - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeNegativeMaskedAddressIPv4() { - IpAddress ipAddress = IpAddress.valueOf("1.2.3.5"); - IpAddress ipAddressMasked; - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, -1); - } - - /** - * Tests making of a masked address for invalid prefix length for IPv6: - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeNegativeMaskedAddressIPv6() { - IpAddress ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8885"); - IpAddress ipAddressMasked; - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, -1); - } - - /** - * Tests making of a masked address for an invalid prefix length for IPv4: - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeTooLongMaskedAddressIPv4() { - IpAddress ipAddress = IpAddress.valueOf("1.2.3.5"); - IpAddress ipAddressMasked; - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 33); - } - - /** - * Tests making of a masked address for an invalid prefix length for IPv6: - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidMakeTooLongMaskedAddressIPv6() { - IpAddress ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8885"); - IpAddress ipAddressMasked; - - ipAddressMasked = IpAddress.makeMaskedAddress(ipAddress, 129); - } - - /** - * Tests if address is zero for IPv4. - */ - @Test - public void testIsZeroIPv4() { - IpAddress normalIP = IpAddress.valueOf("10.0.0.1"); - IpAddress zeroIP = IpAddress.valueOf("0.0.0.0"); - assertFalse(normalIP.isZero()); - assertTrue(zeroIP.isZero()); - } - - /** - * Tests if address is zero for IPv6. - */ - @Test - public void testIsZeroIPv6() { - IpAddress normalIP = IpAddress.valueOf("fe80::1"); - IpAddress zeroIP = IpAddress.valueOf("::"); - assertFalse(normalIP.isZero()); - assertTrue(zeroIP.isZero()); - } - - /** - * Tests if address is self-assigned for IPv4. - */ - @Test - public void testIsSelfAssignedIpv4() { - IpAddress normalIP = IpAddress.valueOf("10.0.0.1"); - IpAddress selfAssignedIP = IpAddress.valueOf("169.1.2.3"); - assertFalse(normalIP.isSelfAssigned()); - assertTrue(selfAssignedIP.isSelfAssigned()); - } - - /** - * Tests comparison of {@link IpAddress} for IPv4. - */ - @Test - public void testComparisonIPv4() { - IpAddress addr1, addr2, addr3, addr4; - - addr1 = IpAddress.valueOf("1.2.3.4"); - addr2 = IpAddress.valueOf("1.2.3.4"); - addr3 = IpAddress.valueOf("1.2.3.3"); - addr4 = IpAddress.valueOf("1.2.3.5"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - - addr1 = IpAddress.valueOf("255.2.3.4"); - addr2 = IpAddress.valueOf("255.2.3.4"); - addr3 = IpAddress.valueOf("255.2.3.3"); - addr4 = IpAddress.valueOf("255.2.3.5"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - } - - /** - * Tests comparison of {@link IpAddress} for IPv6. - */ - @Test - public void testComparisonIPv6() { - IpAddress addr1, addr2, addr3, addr4; - - addr1 = IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - addr2 = IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - addr3 = IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8887"); - addr4 = IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8889"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - - addr1 = IpAddress.valueOf("ffff:2222:3333:4444:5555:6666:7777:8888"); - addr2 = IpAddress.valueOf("ffff:2222:3333:4444:5555:6666:7777:8888"); - addr3 = IpAddress.valueOf("ffff:2222:3333:4444:5555:6666:7777:8887"); - addr4 = IpAddress.valueOf("ffff:2222:3333:4444:5555:6666:7777:8889"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - - addr1 = IpAddress.valueOf("ffff:2222:3333:4444:5555:6666:7777:8888"); - addr2 = IpAddress.valueOf("ffff:2222:3333:4444:5555:6666:7777:8888"); - addr3 = IpAddress.valueOf("ffff:2222:3333:4443:5555:6666:7777:8888"); - addr4 = IpAddress.valueOf("ffff:2222:3333:4445:5555:6666:7777:8888"); - assertTrue(addr1.compareTo(addr2) == 0); - assertTrue(addr1.compareTo(addr3) > 0); - assertTrue(addr1.compareTo(addr4) < 0); - } - - /** - * Tests equality of {@link IpAddress} for IPv4. - */ - @Test - public void testEqualityIPv4() { - new EqualsTester() - .addEqualityGroup(IpAddress.valueOf("1.2.3.4"), - IpAddress.valueOf("1.2.3.4")) - .addEqualityGroup(IpAddress.valueOf("1.2.3.5"), - IpAddress.valueOf("1.2.3.5")) - .addEqualityGroup(IpAddress.valueOf("0.0.0.0"), - IpAddress.valueOf("0.0.0.0")) - .addEqualityGroup(IpAddress.valueOf("255.255.255.255"), - IpAddress.valueOf("255.255.255.255")) - .testEquals(); - } - - /** - * Tests equality of {@link IpAddress} for IPv6. - */ - @Test - public void testEqualityIPv6() { - new EqualsTester() - .addEqualityGroup( - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"), - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888")) - .addEqualityGroup( - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:888a"), - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:888a")) - .addEqualityGroup( - IpAddress.valueOf("::"), - IpAddress.valueOf("::")) - .addEqualityGroup( - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) - .testEquals(); - } - - /** - * Tests object string representation for IPv4. - */ - @Test - public void testToStringIPv4() { - IpAddress ipAddress; - - ipAddress = IpAddress.valueOf("1.2.3.4"); - assertThat(ipAddress.toString(), is("1.2.3.4")); - - ipAddress = IpAddress.valueOf("0.0.0.0"); - assertThat(ipAddress.toString(), is("0.0.0.0")); - - ipAddress = IpAddress.valueOf("255.255.255.255"); - assertThat(ipAddress.toString(), is("255.255.255.255")); - } - - /** - * Tests object string representation for IPv6. - */ - @Test - public void testToStringIPv6() { - IpAddress ipAddress; - - ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - assertThat(ipAddress.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888")); - - ipAddress = IpAddress.valueOf("1111::8888"); - assertThat(ipAddress.toString(), is("1111::8888")); - - ipAddress = IpAddress.valueOf("1111::"); - assertThat(ipAddress.toString(), is("1111::")); - - ipAddress = IpAddress.valueOf("::8888"); - assertThat(ipAddress.toString(), is("::8888")); - - ipAddress = IpAddress.valueOf("::"); - assertThat(ipAddress.toString(), is("::")); - - ipAddress = - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - assertThat(ipAddress.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); - - ipAddress = - IpAddress.valueOf("::1111:2222"); - assertThat(ipAddress.toString(), - is("::1111:2222")); - - ipAddress = - IpAddress.valueOf("1:0:0:1:0:0:2:3"); - assertThat(ipAddress.toString(), - is("1::1:0:0:2:3")); - - ipAddress = - IpAddress.valueOf("::0123:0004"); - assertThat(ipAddress.toString(), - is("::123:4")); - - ipAddress = - IpAddress.valueOf("0:0:1:1:0:0:1:1"); - assertThat(ipAddress.toString(), - is("::1:1:0:0:1:1")); - - ipAddress = - IpAddress.valueOf("1:1a2b::"); - assertThat(ipAddress.toString(), - is("1:1a2b::")); - - ipAddress = - IpAddress.valueOf("0:0:00:00:0000:00:00:000"); - assertThat(ipAddress.toString(), - is("::")); - - ipAddress = - IpAddress.valueOf("0:0:0:1:0:0:0:0"); - assertThat(ipAddress.toString(), - is("0:0:0:1::")); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IpPrefixTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IpPrefixTest.java deleted file mode 100644 index 052a4cbb..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/IpPrefixTest.java +++ /dev/null @@ -1,1080 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Test; - -import com.google.common.testing.EqualsTester; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; - -/** - * Tests for class {@link IpPrefix}. - */ -public class IpPrefixTest { - /** - * Tests the immutability of {@link IpPrefix}. - */ - @Test - public void testImmutable() { - assertThatClassIsImmutableBaseClass(IpPrefix.class); - } - - /** - * Tests the maximum mask length. - */ - @Test - public void testMaxMaskLength() { - assertThat(IpPrefix.MAX_INET_MASK_LENGTH, is(32)); - assertThat(IpPrefix.MAX_INET6_MASK_LENGTH, is(128)); - } - - /** - * Tests returning the IP version of the prefix. - */ - @Test - public void testVersion() { - IpPrefix ipPrefix; - - // IPv4 - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertThat(ipPrefix.version(), is(IpAddress.Version.INET)); - - // IPv6 - ipPrefix = IpPrefix.valueOf("::/0"); - assertThat(ipPrefix.version(), is(IpAddress.Version.INET6)); - } - - /** - * Tests whether the IP version of a prefix is IPv4. - */ - @Test - public void testIsIp4() { - IpPrefix ipPrefix; - - // IPv4 - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertTrue(ipPrefix.isIp4()); - - // IPv6 - ipPrefix = IpPrefix.valueOf("::/0"); - assertFalse(ipPrefix.isIp4()); - } - - /** - * Tests whether the IP version of a prefix is IPv6. - */ - @Test - public void testIsIp6() { - IpPrefix ipPrefix; - - // IPv4 - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertFalse(ipPrefix.isIp6()); - - // IPv6 - ipPrefix = IpPrefix.valueOf("::/0"); - assertTrue(ipPrefix.isIp6()); - } - - /** - * Tests returning the IP address value and IP address prefix length of - * an IPv4 prefix. - */ - @Test - public void testAddressAndPrefixLengthIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1.2.3.0/24"); - assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1.2.3.0"))); - assertThat(ipPrefix.prefixLength(), is(24)); - - ipPrefix = IpPrefix.valueOf("1.2.3.4/24"); - assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1.2.3.0"))); - assertThat(ipPrefix.prefixLength(), is(24)); - - ipPrefix = IpPrefix.valueOf("1.2.3.4/32"); - assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1.2.3.4"))); - assertThat(ipPrefix.prefixLength(), is(32)); - - ipPrefix = IpPrefix.valueOf("1.2.3.5/32"); - assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1.2.3.5"))); - assertThat(ipPrefix.prefixLength(), is(32)); - - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("0.0.0.0"))); - assertThat(ipPrefix.prefixLength(), is(0)); - - ipPrefix = IpPrefix.valueOf("255.255.255.255/32"); - assertThat(ipPrefix.address(), - equalTo(IpAddress.valueOf("255.255.255.255"))); - assertThat(ipPrefix.prefixLength(), is(32)); - } - - /** - * Tests returning the IP address value and IP address prefix length of - * an IPv6 prefix. - */ - @Test - public void testAddressAndPrefixLengthIPv6() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1100::/8"); - assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1100::"))); - assertThat(ipPrefix.prefixLength(), is(8)); - - ipPrefix = - IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/8"); - assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("1100::"))); - assertThat(ipPrefix.prefixLength(), is(8)); - - ipPrefix = - IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8800/120"); - assertThat(ipPrefix.address(), - equalTo(IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8800"))); - assertThat(ipPrefix.prefixLength(), is(120)); - - ipPrefix = - IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/128"); - assertThat(ipPrefix.address(), - equalTo(IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8885"))); - assertThat(ipPrefix.prefixLength(), is(128)); - - ipPrefix = IpPrefix.valueOf("::/0"); - assertThat(ipPrefix.address(), equalTo(IpAddress.valueOf("::"))); - assertThat(ipPrefix.prefixLength(), is(0)); - - ipPrefix = - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertThat(ipPrefix.address(), - equalTo(IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - assertThat(ipPrefix.prefixLength(), is(128)); - - ipPrefix = - IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/64"); - assertThat(ipPrefix.address(), - equalTo(IpAddress.valueOf("1111:2222:3333:4444::"))); - assertThat(ipPrefix.prefixLength(), is(64)); - } - - /** - * Tests getting the Ip4Prefix and Ip6Prefix view of the IP prefix. - */ - @Test - public void testGetIp4AndIp6PrefixView() { - IpPrefix ipPrefix; - Ip4Prefix ip4Prefix; - Ip6Prefix ip6Prefix; - - // Pure IPv4 IpPrefix - ipPrefix = IpPrefix.valueOf("1.2.3.0/24"); - ip4Prefix = ipPrefix.getIp4Prefix(); - ip6Prefix = ipPrefix.getIp6Prefix(); - assertThat(ip4Prefix.toString(), is("1.2.3.0/24")); - assertNull(ip6Prefix); - - // IPv4 IpPrefix that is Ip4Prefix - ipPrefix = Ip4Prefix.valueOf("1.2.3.0/24"); - ip4Prefix = ipPrefix.getIp4Prefix(); - ip6Prefix = ipPrefix.getIp6Prefix(); - assertThat(ip4Prefix.toString(), is("1.2.3.0/24")); - assertNull(ip6Prefix); - - // Pure IPv6 IpPrefix - ipPrefix = IpPrefix.valueOf("1111:2222::/64"); - ip4Prefix = ipPrefix.getIp4Prefix(); - ip6Prefix = ipPrefix.getIp6Prefix(); - assertNull(ip4Prefix); - assertThat(ip6Prefix.toString(), is("1111:2222::/64")); - - // IPv6 IpPrefix that is Ip6Prefix - ipPrefix = Ip6Prefix.valueOf("1111:2222::/64"); - ip4Prefix = ipPrefix.getIp4Prefix(); - ip6Prefix = ipPrefix.getIp6Prefix(); - assertNull(ip4Prefix); - assertThat(ip6Prefix.toString(), is("1111:2222::/64")); - } - - /** - * Tests valueOf() converter for IPv4 integer value. - */ - @Test - public void testValueOfForIntegerIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf(0x01020304, 24); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = IpPrefix.valueOf(0x01020304, 32); - assertThat(ipPrefix.toString(), is("1.2.3.4/32")); - - ipPrefix = IpPrefix.valueOf(0x01020305, 32); - assertThat(ipPrefix.toString(), is("1.2.3.5/32")); - - ipPrefix = IpPrefix.valueOf(0, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf(0, 32); - assertThat(ipPrefix.toString(), is("0.0.0.0/32")); - - ipPrefix = IpPrefix.valueOf(0xffffffff, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf(0xffffffff, 16); - assertThat(ipPrefix.toString(), is("255.255.0.0/16")); - - ipPrefix = IpPrefix.valueOf(0xffffffff, 32); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests invalid valueOf() converter for IPv4 integer value and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIntegerNegativePrefixLengthIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf(0x01020304, -1); - } - - /** - * Tests invalid valueOf() converter for IPv4 integer value and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIntegerTooLongPrefixLengthIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf(0x01020304, 33); - } - - /** - * Tests valueOf() converter for IPv4 byte array. - */ - @Test - public void testValueOfByteArrayIPv4() { - IpPrefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 24); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 32); - assertThat(ipPrefix.toString(), is("1.2.3.4/32")); - - value = new byte[] {1, 2, 3, 5}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 32); - assertThat(ipPrefix.toString(), is("1.2.3.5/32")); - - value = new byte[] {0, 0, 0, 0}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 32); - assertThat(ipPrefix.toString(), is("0.0.0.0/32")); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 16); - assertThat(ipPrefix.toString(), is("255.255.0.0/16")); - - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 32); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests valueOf() converter for IPv6 byte array. - */ - @Test - public void testValueOfByteArrayIPv6() { - IpPrefix ipPrefix; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, (byte) 0x88, (byte) 0x88}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 120); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8800/120")); - - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 128); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888/128")); - - value = new byte[] {0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 0); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 128); - assertThat(ipPrefix.toString(), is("::/128")); - - value = new byte[] {(byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 0); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 64); - assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64")); - - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 128); - assertThat(ipPrefix.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")); - } - - /** - * Tests invalid valueOf() converter for a null array for IPv4. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullArrayIPv4() { - IpPrefix ipPrefix; - byte[] value; - - value = null; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 24); - } - - /** - * Tests invalid valueOf() converter for a null array for IPv6. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullArrayIPv6() { - IpPrefix ipPrefix; - byte[] value; - - value = null; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 120); - } - - /** - * Tests invalid valueOf() converter for a short array for IPv4. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfShortArrayIPv4() { - IpPrefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 24); - } - - /** - * Tests invalid valueOf() converter for a short array for IPv6. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfShortArrayIPv6() { - IpPrefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 120); - } - - /** - * Tests invalid valueOf() converter for IPv4 byte array and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfByteArrayNegativePrefixLengthIPv4() { - IpPrefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, -1); - } - - /** - * Tests invalid valueOf() converter for IPv6 byte array and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfByteArrayNegativePrefixLengthIPv6() { - IpPrefix ipPrefix; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, (byte) 0x88, (byte) 0x88}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, -1); - } - - /** - * Tests invalid valueOf() converter for IPv4 byte array and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfByteArrayTooLongPrefixLengthIPv4() { - IpPrefix ipPrefix; - byte[] value; - - value = new byte[] {1, 2, 3, 4}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET, value, 33); - } - - /** - * Tests invalid valueOf() converter for IPv6 byte array and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfByteArrayTooLongPrefixLengthIPv6() { - IpPrefix ipPrefix; - byte[] value; - - value = new byte[] {0x11, 0x11, 0x22, 0x22, - 0x33, 0x33, 0x44, 0x44, - 0x55, 0x55, 0x66, 0x66, - 0x77, 0x77, (byte) 0x88, (byte) 0x88}; - ipPrefix = IpPrefix.valueOf(IpAddress.Version.INET6, value, 129); - } - - /** - * Tests valueOf() converter for IPv4 address. - */ - @Test - public void testValueOfAddressIPv4() { - IpAddress ipAddress; - IpPrefix ipPrefix; - - ipAddress = IpAddress.valueOf("1.2.3.4"); - ipPrefix = IpPrefix.valueOf(ipAddress, 24); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = IpPrefix.valueOf(ipAddress, 32); - assertThat(ipPrefix.toString(), is("1.2.3.4/32")); - - ipAddress = IpAddress.valueOf("1.2.3.5"); - ipPrefix = IpPrefix.valueOf(ipAddress, 32); - assertThat(ipPrefix.toString(), is("1.2.3.5/32")); - - ipAddress = IpAddress.valueOf("0.0.0.0"); - ipPrefix = IpPrefix.valueOf(ipAddress, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf(ipAddress, 32); - assertThat(ipPrefix.toString(), is("0.0.0.0/32")); - - ipAddress = IpAddress.valueOf("255.255.255.255"); - ipPrefix = IpPrefix.valueOf(ipAddress, 0); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf(ipAddress, 16); - assertThat(ipPrefix.toString(), is("255.255.0.0/16")); - - ipPrefix = IpPrefix.valueOf(ipAddress, 32); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests valueOf() converter for IPv6 address. - */ - @Test - public void testValueOfAddressIPv6() { - IpAddress ipAddress; - IpPrefix ipPrefix; - - ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - ipPrefix = IpPrefix.valueOf(ipAddress, 120); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8800/120")); - - ipPrefix = IpPrefix.valueOf(ipAddress, 128); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888/128")); - - ipAddress = IpAddress.valueOf("::"); - ipPrefix = IpPrefix.valueOf(ipAddress, 0); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = IpPrefix.valueOf(ipAddress, 128); - assertThat(ipPrefix.toString(), is("::/128")); - - ipAddress = - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); - ipPrefix = IpPrefix.valueOf(ipAddress, 0); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = IpPrefix.valueOf(ipAddress, 64); - assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64")); - - ipPrefix = IpPrefix.valueOf(ipAddress, 128); - assertThat(ipPrefix.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")); - } - - /** - * Tests invalid valueOf() converter for a null IP address. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullAddress() { - IpAddress ipAddress; - IpPrefix ipPrefix; - - ipAddress = null; - ipPrefix = IpPrefix.valueOf(ipAddress, 24); - } - - /** - * Tests invalid valueOf() converter for IPv4 address and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfAddressNegativePrefixLengthIPv4() { - IpAddress ipAddress; - IpPrefix ipPrefix; - - ipAddress = IpAddress.valueOf("1.2.3.4"); - ipPrefix = IpPrefix.valueOf(ipAddress, -1); - } - - /** - * Tests invalid valueOf() converter for IPv6 address and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfAddressNegativePrefixLengthIPv6() { - IpAddress ipAddress; - IpPrefix ipPrefix; - - ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - ipPrefix = IpPrefix.valueOf(ipAddress, -1); - } - - /** - * Tests invalid valueOf() converter for IPv4 address and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfAddressTooLongPrefixLengthIPv4() { - IpAddress ipAddress; - IpPrefix ipPrefix; - - ipAddress = IpAddress.valueOf("1.2.3.4"); - ipPrefix = IpPrefix.valueOf(ipAddress, 33); - } - - /** - * Tests invalid valueOf() converter for IPv6 address and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfAddressTooLongPrefixLengthIPv6() { - IpAddress ipAddress; - IpPrefix ipPrefix; - - ipAddress = - IpAddress.valueOf("1111:2222:3333:4444:5555:6666:7777:8888"); - ipPrefix = IpPrefix.valueOf(ipAddress, 129); - } - - /** - * Tests valueOf() converter for IPv4 string. - */ - @Test - public void testValueOfStringIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1.2.3.4/24"); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = IpPrefix.valueOf("1.2.3.4/32"); - assertThat(ipPrefix.toString(), is("1.2.3.4/32")); - - ipPrefix = IpPrefix.valueOf("1.2.3.5/32"); - assertThat(ipPrefix.toString(), is("1.2.3.5/32")); - - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf("0.0.0.0/32"); - assertThat(ipPrefix.toString(), is("0.0.0.0/32")); - - ipPrefix = IpPrefix.valueOf("255.255.255.255/0"); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf("255.255.255.255/16"); - assertThat(ipPrefix.toString(), is("255.255.0.0/16")); - - ipPrefix = IpPrefix.valueOf("255.255.255.255/32"); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests valueOf() converter for IPv6 string. - */ - @Test - public void testValueOfStringIPv6() { - IpPrefix ipPrefix; - - ipPrefix = - IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/120"); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8800/120")); - - ipPrefix = - IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/128"); - assertThat(ipPrefix.toString(), - is("1111:2222:3333:4444:5555:6666:7777:8888/128")); - - ipPrefix = IpPrefix.valueOf("::/0"); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = IpPrefix.valueOf("::/128"); - assertThat(ipPrefix.toString(), is("::/128")); - - ipPrefix = - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/0"); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"); - assertThat(ipPrefix.toString(), is("ffff:ffff:ffff:ffff::/64")); - - ipPrefix = - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertThat(ipPrefix.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")); - } - - /** - * Tests invalid valueOf() converter for a null string. - */ - @Test(expected = NullPointerException.class) - public void testInvalidValueOfNullString() { - IpPrefix ipPrefix; - String fromString; - - fromString = null; - ipPrefix = IpPrefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an empty string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfEmptyString() { - IpPrefix ipPrefix; - String fromString; - - fromString = ""; - ipPrefix = IpPrefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for an incorrect string. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfIncorrectString() { - IpPrefix ipPrefix; - String fromString; - - fromString = "NoSuchIpPrefix"; - ipPrefix = IpPrefix.valueOf(fromString); - } - - /** - * Tests invalid valueOf() converter for IPv4 string and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfStringNegativePrefixLengthIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1.2.3.4/-1"); - } - - /** - * Tests invalid valueOf() converter for IPv6 string and - * negative prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfStringNegativePrefixLengthIPv6() { - IpPrefix ipPrefix; - - ipPrefix = - IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/-1"); - } - - /** - * Tests invalid valueOf() converter for IPv4 string and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfStringTooLongPrefixLengthIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1.2.3.4/33"); - } - - /** - * Tests invalid valueOf() converter for IPv6 string and - * too long prefix length. - */ - @Test(expected = IllegalArgumentException.class) - public void testInvalidValueOfStringTooLongPrefixLengthIPv6() { - IpPrefix ipPrefix; - - ipPrefix = - IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8888/129"); - } - - /** - * Tests IP prefix contains another IP prefix for IPv4. - */ - @Test - public void testContainsIpPrefixIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1.2.0.0/24"); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/32"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.4/32"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/16"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.3.0.0/24"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/16"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/0"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32"))); - - ipPrefix = IpPrefix.valueOf("1.2.0.0/32"); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/32"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.4/32"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/16"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.3.0.0/24"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/16"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/0"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32"))); - - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/32"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.4/32"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/16"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("1.3.0.0/24"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/16"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/0"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32"))); - - ipPrefix = IpPrefix.valueOf("255.255.255.255/32"); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/32"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.4/32"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/16"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.3.0.0/24"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/16"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("0.0.0.0/0"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32"))); - - // Test when there is a mistmatch in the compared IP address families - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1111:2222:3333:4444::/120"))); - ipPrefix = IpPrefix.valueOf("255.255.255.255/32"); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - } - - /** - * Tests IP prefix contains another IP prefix for IPv6. - */ - @Test - public void testContainsIpPrefixIPv6() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444::/120"); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/120"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/128"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::1/128"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/64"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4445::/120"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/64"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/0"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - - ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444::/128"); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/120"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/128"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::1/128"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/64"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4445::/120"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/64"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/0"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - - ipPrefix = IpPrefix.valueOf("::/0"); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/120"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/128"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::1/128"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/64"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4445::/120"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("::/64"))); - assertTrue(ipPrefix.contains(IpPrefix.valueOf("::/0"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - - ipPrefix = - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/120"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/128"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::1/128"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4444::/64"))); - assertFalse(ipPrefix.contains( - IpPrefix.valueOf("1111:2222:3333:4445::/120"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/64"))); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("::/0"))); - assertTrue(ipPrefix.contains( - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"))); - - // Test when there is a mistmatch in the compared IP address families - ipPrefix = IpPrefix.valueOf("::/0"); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("1.2.0.0/24"))); - ipPrefix = IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertFalse(ipPrefix.contains(IpPrefix.valueOf("255.255.255.255/32"))); - } - - /** - * Tests IP prefix contains IP address for IPv4. - */ - @Test - public void testContainsIpAddressIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1.2.0.0/24"); - assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.0"))); - assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.4"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("1.3.0.0"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("0.0.0.0"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("255.255.255.255"))); - - ipPrefix = IpPrefix.valueOf("1.2.0.0/32"); - assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.0"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("1.2.0.4"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("1.3.0.0"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("0.0.0.0"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("255.255.255.255"))); - - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.0"))); - assertTrue(ipPrefix.contains(IpAddress.valueOf("1.2.0.4"))); - assertTrue(ipPrefix.contains(IpAddress.valueOf("1.3.0.0"))); - assertTrue(ipPrefix.contains(IpAddress.valueOf("0.0.0.0"))); - assertTrue(ipPrefix.contains(IpAddress.valueOf("255.255.255.255"))); - - ipPrefix = IpPrefix.valueOf("255.255.255.255/32"); - assertFalse(ipPrefix.contains(IpAddress.valueOf("1.2.0.0"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("1.2.0.4"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("1.3.0.0"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("0.0.0.0"))); - assertTrue(ipPrefix.contains(IpAddress.valueOf("255.255.255.255"))); - - // Test when there is a mistmatch in the compared IP address families - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertFalse(ipPrefix.contains(IpAddress.valueOf("1111:2222:3333:4444::"))); - ipPrefix = IpPrefix.valueOf("255.255.255.255/32"); - assertFalse(ipPrefix.contains(IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - } - - /** - * Tests IP prefix contains IP address for IPv6. - */ - @Test - public void testContainsIpAddressIPv6() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444::/120"); - assertTrue(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4444::"))); - assertTrue(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4444::1"))); - assertFalse(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4445::"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("::"))); - assertFalse(ipPrefix.contains( - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - - ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444::/128"); - assertTrue(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4444::"))); - assertFalse(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4444::1"))); - assertFalse(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4445::"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("::"))); - assertFalse(ipPrefix.contains( - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - - ipPrefix = IpPrefix.valueOf("::/0"); - assertTrue(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4444::"))); - assertTrue(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4444::1"))); - assertTrue(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4445::"))); - assertTrue(ipPrefix.contains(IpAddress.valueOf("::"))); - assertTrue(ipPrefix.contains( - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - - ipPrefix = - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertFalse(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4444::"))); - assertFalse(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4444::1"))); - assertFalse(ipPrefix.contains( - IpAddress.valueOf("1111:2222:3333:4445::"))); - assertFalse(ipPrefix.contains(IpAddress.valueOf("::"))); - assertTrue(ipPrefix.contains( - IpAddress.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))); - - // Test when there is a mistmatch in the compared IP address families - ipPrefix = IpPrefix.valueOf("::/0"); - assertFalse(ipPrefix.contains(IpAddress.valueOf("1.2.0.0"))); - ipPrefix = IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertFalse(ipPrefix.contains(IpAddress.valueOf("255.255.255.255"))); - } - - /** - * Tests equality of {@link IpPrefix} for IPv4. - */ - @Test - public void testEqualityIPv4() { - new EqualsTester() - .addEqualityGroup(IpPrefix.valueOf("1.2.0.0/24"), - IpPrefix.valueOf("1.2.0.0/24"), - IpPrefix.valueOf("1.2.0.4/24")) - .addEqualityGroup(IpPrefix.valueOf("1.2.0.0/16"), - IpPrefix.valueOf("1.2.0.0/16")) - .addEqualityGroup(IpPrefix.valueOf("1.2.0.0/32"), - IpPrefix.valueOf("1.2.0.0/32")) - .addEqualityGroup(IpPrefix.valueOf("1.3.0.0/24"), - IpPrefix.valueOf("1.3.0.0/24")) - .addEqualityGroup(IpPrefix.valueOf("0.0.0.0/0"), - IpPrefix.valueOf("0.0.0.0/0")) - .addEqualityGroup(IpPrefix.valueOf("255.255.255.255/32"), - IpPrefix.valueOf("255.255.255.255/32")) - .testEquals(); - } - - /** - * Tests equality of {@link IpPrefix} for IPv6. - */ - @Test - public void testEqualityIPv6() { - new EqualsTester() - .addEqualityGroup( - IpPrefix.valueOf("1111:2222:3333:4444::/120"), - IpPrefix.valueOf("1111:2222:3333:4444::1/120"), - IpPrefix.valueOf("1111:2222:3333:4444::/120")) - .addEqualityGroup( - IpPrefix.valueOf("1111:2222:3333:4444::/64"), - IpPrefix.valueOf("1111:2222:3333:4444::/64")) - .addEqualityGroup( - IpPrefix.valueOf("1111:2222:3333:4444::/128"), - IpPrefix.valueOf("1111:2222:3333:4444::/128")) - .addEqualityGroup( - IpPrefix.valueOf("1111:2222:3333:4445::/64"), - IpPrefix.valueOf("1111:2222:3333:4445::/64")) - .addEqualityGroup( - IpPrefix.valueOf("::/0"), - IpPrefix.valueOf("::/0")) - .addEqualityGroup( - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"), - IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")) - .testEquals(); - } - - /** - * Tests object string representation for IPv4. - */ - @Test - public void testToStringIPv4() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1.2.3.0/24"); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = IpPrefix.valueOf("1.2.3.4/24"); - assertThat(ipPrefix.toString(), is("1.2.3.0/24")); - - ipPrefix = IpPrefix.valueOf("0.0.0.0/0"); - assertThat(ipPrefix.toString(), is("0.0.0.0/0")); - - ipPrefix = IpPrefix.valueOf("255.255.255.255/32"); - assertThat(ipPrefix.toString(), is("255.255.255.255/32")); - } - - /** - * Tests object string representation for IPv6. - */ - @Test - public void testToStringIPv6() { - IpPrefix ipPrefix; - - ipPrefix = IpPrefix.valueOf("1100::/8"); - assertThat(ipPrefix.toString(), is("1100::/8")); - - ipPrefix = IpPrefix.valueOf("1111:2222:3333:4444:5555:6666:7777:8885/8"); - assertThat(ipPrefix.toString(), is("1100::/8")); - - ipPrefix = IpPrefix.valueOf("::/0"); - assertThat(ipPrefix.toString(), is("::/0")); - - ipPrefix = IpPrefix.valueOf("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"); - assertThat(ipPrefix.toString(), - is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/LLCTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/LLCTest.java deleted file mode 100644 index 39bb72f4..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/LLCTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; - -import java.nio.ByteBuffer; - -import static org.junit.Assert.assertEquals; - -/** - * Unit tests for LLC class. - */ -public class LLCTest { - - private Deserializer<LLC> deserializer; - - private byte dsap = 10; - private byte ssap = 20; - private byte ctrl = 30; - - private byte[] bytes; - - @Before - public void setUp() throws Exception { - deserializer = LLC.deserializer(); - - ByteBuffer bb = ByteBuffer.allocate(LLC.LLC_HEADER_LENGTH); - - bb.put(dsap); - bb.put(ssap); - bb.put(ctrl); - - bytes = bb.array(); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, bytes); - } - - @Test - public void testDeserialize() throws Exception { - LLC llc = deserializer.deserialize(bytes, 0, bytes.length); - - assertEquals(dsap, llc.getDsap()); - assertEquals(ssap, llc.getSsap()); - assertEquals(ctrl, llc.getCtrl()); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/LLDPTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/LLDPTest.java deleted file mode 100644 index 95b0b04a..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/LLDPTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Unit tests for the LLDP class. - */ -public class LLDPTest { - - private Deserializer<LLDP> deserializer; - - private byte[] chassisValue = new byte[] {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}; - private byte[] portValue = new byte[] {0x1, 0x2, 0x3, 0x4, 0x5}; - private byte[] ttlValue = new byte[] {0x0, 0x20}; - - private short optionalTlvSize = 6; - private byte[] optionalTlvValue = new byte[] {0x6, 0x5, 0x4, 0x3, 0x2, 0x1}; - - private byte[] bytes; - - @Before - public void setUp() throws Exception { - deserializer = LLDP.deserializer(); - - // Each TLV is 2 bytes for the type+length, plus the size of the value - // There are 2 zero-bytes at the end - ByteBuffer bb = ByteBuffer.allocate(2 + LLDP.CHASSIS_TLV_SIZE + - 2 + LLDP.PORT_TLV_SIZE + - 2 + LLDP.TTL_TLV_SIZE + - 2 + optionalTlvSize + - 2); - - // Chassis TLV - bb.putShort(getTypeLength(LLDP.CHASSIS_TLV_TYPE, LLDP.CHASSIS_TLV_SIZE)); - bb.put(chassisValue); - - // Port TLV - bb.putShort(getTypeLength(LLDP.PORT_TLV_TYPE, LLDP.PORT_TLV_SIZE)); - bb.put(portValue); - - // TTL TLV - bb.putShort(getTypeLength(LLDP.TTL_TLV_TYPE, LLDP.TTL_TLV_SIZE)); - bb.put(ttlValue); - - // Optional TLV - bb.putShort(getTypeLength(LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE, optionalTlvSize)); - bb.put(optionalTlvValue); - - bb.putShort((short) 0); - - bytes = bb.array(); - - } - - private short getTypeLength(byte type, short length) { - return (short) ((0x7f & type) << 9 | 0x1ff & length); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, bytes); - } - - @Test - public void testDeserialize() throws Exception { - LLDP lldp = deserializer.deserialize(bytes, 0, bytes.length); - - assertEquals(LLDP.CHASSIS_TLV_TYPE, lldp.getChassisId().getType()); - assertEquals(LLDP.CHASSIS_TLV_SIZE, lldp.getChassisId().getLength()); - assertTrue(Arrays.equals(chassisValue, lldp.getChassisId().getValue())); - - assertEquals(LLDP.PORT_TLV_TYPE, lldp.getPortId().getType()); - assertEquals(LLDP.PORT_TLV_SIZE, lldp.getPortId().getLength()); - assertTrue(Arrays.equals(portValue, lldp.getPortId().getValue())); - - assertEquals(LLDP.TTL_TLV_TYPE, lldp.getTtl().getType()); - assertEquals(LLDP.TTL_TLV_SIZE, lldp.getTtl().getLength()); - assertTrue(Arrays.equals(ttlValue, lldp.getTtl().getValue())); - - assertEquals(1, lldp.getOptionalTLVList().size()); - LLDPTLV optionalTlv = lldp.getOptionalTLVList().get(0); - - assertEquals(LLDPOrganizationalTLV.ORGANIZATIONAL_TLV_TYPE, optionalTlv.getType()); - assertEquals(optionalTlvSize, optionalTlv.getLength()); - assertTrue(Arrays.equals(optionalTlvValue, optionalTlv.getValue())); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/MplsTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/MplsTest.java deleted file mode 100644 index 2ab8ff98..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/MplsTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; - -import java.nio.ByteBuffer; -import java.util.HashMap; - -import static org.junit.Assert.assertEquals; - -/** - * Unit tests for MPLS class. - */ -public class MplsTest { - - private Deserializer<MPLS> deserializer; - - private int label = 1048575; - private byte bos = 1; - private byte ttl = 20; - private byte protocol = MPLS.PROTOCOL_IPV4; - - private byte[] bytes; - - @Before - public void setUp() throws Exception { - // Replace normal deserializer map with an empty map. This will cause - // the DataDeserializer to be used which will silently handle 0-byte input. - MPLS.protocolDeserializerMap = new HashMap<>(); - - deserializer = MPLS.deserializer(); - - ByteBuffer bb = ByteBuffer.allocate(MPLS.HEADER_LENGTH); - bb.putInt(((label & 0x000fffff) << 12) | ((bos & 0x1) << 8 | (ttl & 0xff))); - - bytes = bb.array(); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, bytes); - } - - @Test - public void testDeserialize() throws Exception { - MPLS mpls = deserializer.deserialize(bytes, 0, bytes.length); - - assertEquals(label, mpls.label); - assertEquals(bos, mpls.bos); - assertEquals(ttl, mpls.ttl); - assertEquals(protocol, mpls.protocol); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/PIMTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/PIMTest.java deleted file mode 100644 index 7fba3cd7..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/PIMTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.Before; -import org.junit.Test; -import org.onlab.packet.pim.PIMAddrUnicast; -import org.onlab.packet.pim.PIMHello; -import org.onlab.packet.pim.PIMJoinPrune; - -import static junit.framework.Assert.assertTrue; - -public final class PIMTest { - - public static final String SADDR = "10.2.1.2"; - public static final String PIMADDR = "224.0.0.13"; - public static final String PIMUADDR = "10.23.3.5"; - - public static final String SADDR1 = "10.1.1.1/32"; - public static final String SADDR2 = "10.1.2.1/32"; - public static final String GADDR1 = "232.1.1.1/32"; - public static final String GADDR2 = "232.1.2.1/32"; - - public static final String CPSTR1 = "of:deadbeefball/8"; - public static final String CPSTR2 = "of:deadbeefcafe/3"; - public static final String CPSTR3 = "of:2badcafef00d/3"; - - private Deserializer<PIM> deserializer; - - private PIM pimHello; - private PIMHello hello; - - private PIM pimJoinPrune; - private PIMJoinPrune joinPrune; - - /** - * Create PIM Hello and Join/Prune packets to be used in testing. - * - * @throws Exception if packet creation fails - */ - @Before - public void setUp() throws Exception { - - // Create a PIM Hello - pimHello = new PIM(); - pimHello.setVersion((byte) 2); - pimHello.setPIMType((byte) PIM.TYPE_HELLO); - pimHello.setChecksum((short) 0); - - hello = new PIMHello(); - hello.createDefaultOptions(); - pimHello.setPayload(hello); - hello.setParent(pimHello); - - // Create PIM Join Prune - pimJoinPrune = new PIM(); - pimJoinPrune.setVersion((byte) 2); - pimJoinPrune.setPIMType((byte) PIM.TYPE_JOIN_PRUNE_REQUEST); - pimJoinPrune.setChecksum((short) 0); - - joinPrune = new PIMJoinPrune(); - joinPrune.setUpstreamAddr(new PIMAddrUnicast(SADDR)); - joinPrune.addJoin(GADDR1, SADDR1); - joinPrune.addJoin(GADDR2, SADDR2); - joinPrune.addPrune(GADDR1, SADDR2); - joinPrune.addPrune(GADDR2, SADDR1); - - pimJoinPrune.setPayload(joinPrune); - joinPrune.setParent(pimJoinPrune); - - deserializer = PIM.deserializer(); - } - - /** - * Make sure our deserializer throws an exception if we recieve bad input. - * - * @throws Exception if we are given bad input. - */ - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - /** - * Verify we throw an exception if we receive a truncated Join/Prune message. - * - * @throws Exception if we receive a truncated Join/Prune message. - */ - @Test - public void testDeserializeTruncated() throws Exception { - byte [] bits = pimJoinPrune.serialize(); - PacketTestUtils.testDeserializeTruncated(deserializer, bits); - } - - /** - * Verify that we correctly deserialize hello messages. - * - * @throws Exception if our input is bad or truncated. - */ - @Test - public void testDeserializeHello() throws Exception { - byte [] data = pimHello.serialize(); - PIM pim = deserializer.deserialize(data, 0, data.length); - assertTrue(pim.equals(pimHello)); - } - - /** - * Verify that we correctly deserialize Join/Prune messages. - * - * @throws Exception if our input is bad or truncated. - */ - @Test - public void testDeserializeJoinPrune() throws Exception { - byte [] data = pimJoinPrune.serialize(); - PIM pim = deserializer.deserialize(data, 0, data.length); - assertTrue(pim.equals(pimJoinPrune)); - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/PacketTestUtils.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/PacketTestUtils.java deleted file mode 100644 index 209b1d27..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/PacketTestUtils.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import java.nio.ByteBuffer; - -import static junit.framework.TestCase.fail; -import static org.junit.Assert.assertTrue; - -/** - * Utilities for testing packet methods. - */ -public final class PacketTestUtils { - - private PacketTestUtils() { - } - - /** - * Tests that the Deserializer function is resilient to bad input parameters - * such as null input, negative offset and length, etc. - * - * @param deserializer deserializer function to test - */ - public static void testDeserializeBadInput(Deserializer deserializer) { - byte[] bytes = ByteBuffer.allocate(4).array(); - - try { - deserializer.deserialize(null, 0, 4); - fail("NullPointerException was not thrown"); - } catch (NullPointerException e) { - assertTrue(true); - } catch (DeserializationException e) { - fail("NullPointerException was not thrown"); - } - - // input byte array length, offset and length don't make sense - expectDeserializationException(deserializer, bytes, -1, 0); - expectDeserializationException(deserializer, bytes, 0, -1); - expectDeserializationException(deserializer, bytes, 0, 5); - expectDeserializationException(deserializer, bytes, 2, 3); - expectDeserializationException(deserializer, bytes, 5, 0); - } - - /** - * Tests that the Deserializer function is resilient to truncated input, or - * cases where the input byte array does not contain enough bytes to - * deserialize the packet. - * - * @param deserializer deserializer function to test - * @param header byte array of a full-size packet - */ - public static void testDeserializeTruncated(Deserializer deserializer, - byte[] header) { - byte[] truncated; - - for (int i = 0; i < header.length; i++) { - truncated = new byte[i]; - - ByteBuffer.wrap(header).get(truncated); - - expectDeserializationException(deserializer, truncated, 0, truncated.length); - } - } - - /** - * Run the given deserializer function against the given inputs and verify - * that a DeserializationException is thrown. The the test will fail if a - * DeserializationException is not thrown by the deserializer function. - * - * @param deserializer deserializer function to test - * @param bytes input byte array - * @param offset input offset - * @param length input length - */ - public static void expectDeserializationException(Deserializer deserializer, - byte[] bytes, int offset, int length) { - try { - deserializer.deserialize(bytes, offset, length); - fail("DeserializationException was not thrown"); - } catch (DeserializationException e) { - assertTrue(true); - } - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/TCPTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/TCPTest.java deleted file mode 100644 index faab5c2c..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/TCPTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link TCP}. - */ -public class TCPTest { - private static final byte[] IPV4_SOURCE_ADDRESS = { - (byte) 192, (byte) 168, (byte) 1, (byte) 1 - }; - private static final byte[] IPV4_DESTINATION_ADDRESS = { - (byte) 192, (byte) 168, (byte) 1, (byte) 2 - }; - private static final byte[] IPV6_SOURCE_ADDRESS = { - (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 - }; - private static final byte[] IPV6_DESTINATION_ADDRESS = { - (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02 - }; - - private static IPv4 ipv4 = new IPv4(); - private static IPv6 ipv6 = new IPv6(); - private static byte[] bytePacketTCP4 = { - (byte) 0x00, (byte) 0x50, (byte) 0x00, (byte) 0x60, // src,dst port - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10, // seq - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20, // ack - (byte) 0x50, (byte) 0x02, // offset,flag - (byte) 0x10, (byte) 0x00, // window - (byte) 0x1b, (byte) 0xae, // checksum - (byte) 0x00, (byte) 0x01 // urgent - }; - private static byte[] bytePacketTCP6 = { - (byte) 0x00, (byte) 0x50, (byte) 0x00, (byte) 0x60, // src,dst port - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10, // seq - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x20, // ack - (byte) 0x50, (byte) 0x02, // offset,flag - (byte) 0x10, (byte) 0x00, // window - (byte) 0xa1, (byte) 0xfd, // checksum - (byte) 0x00, (byte) 0x01 // urgent - }; - - private static Deserializer<TCP> deserializer; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - deserializer = TCP.deserializer(); - - ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS)); - ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS)); - ipv4.setProtocol(IPv4.PROTOCOL_TCP); - - ipv6.setSourceAddress(IPV6_SOURCE_ADDRESS); - ipv6.setDestinationAddress(IPV6_DESTINATION_ADDRESS); - ipv6.setNextHeader(IPv6.PROTOCOL_TCP); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - TCP tcp = new TCP(); - tcp.setSourcePort(0x50); - tcp.setDestinationPort(0x60); - tcp.setSequence(0x10); - tcp.setAcknowledge(0x20); - tcp.setDataOffset((byte) 0x5); - tcp.setFlags((short) 0x2); - tcp.setWindowSize((short) 0x1000); - tcp.setUrgentPointer((short) 0x1); - - tcp.setParent(ipv4); - assertArrayEquals(bytePacketTCP4, tcp.serialize()); - tcp.resetChecksum(); - tcp.setParent(ipv6); - assertArrayEquals(bytePacketTCP6, tcp.serialize()); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, bytePacketTCP4); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws Exception { - TCP tcp = deserializer.deserialize(bytePacketTCP4, 0, bytePacketTCP4.length); - - assertThat(tcp.getSourcePort(), is(0x50)); - assertThat(tcp.getDestinationPort(), is(0x60)); - assertThat(tcp.getSequence(), is(0x10)); - assertThat(tcp.getAcknowledge(), is(0x20)); - assertThat(tcp.getDataOffset(), is((byte) 0x5)); - assertThat(tcp.getFlags(), is((short) 0x2)); - assertThat(tcp.getWindowSize(), is((short) 0x1000)); - assertThat(tcp.getUrgentPointer(), is((short) 0x1)); - assertThat(tcp.getChecksum(), is((short) 0x1bae)); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - TCP tcp1 = new TCP(); - tcp1.setSourcePort(0x50); - tcp1.setDestinationPort(0x60); - tcp1.setSequence(0x10); - tcp1.setAcknowledge(0x20); - tcp1.setDataOffset((byte) 0x5); - tcp1.setFlags((short) 0x2); - tcp1.setWindowSize((short) 0x1000); - tcp1.setUrgentPointer((short) 0x1); - - TCP tcp2 = new TCP(); - tcp2.setSourcePort(0x70); - tcp2.setDestinationPort(0x60); - tcp2.setSequence(0x10); - tcp2.setAcknowledge(0x20); - tcp2.setDataOffset((byte) 0x5); - tcp2.setFlags((short) 0x2); - tcp2.setWindowSize((short) 0x1000); - tcp2.setUrgentPointer((short) 0x1); - - assertTrue(tcp1.equals(tcp1)); - assertFalse(tcp1.equals(tcp2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/UDPTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/UDPTest.java deleted file mode 100644 index ba453f61..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/UDPTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet; - -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link UDP}. - */ -public class UDPTest { - private static final byte[] IPV4_SOURCE_ADDRESS = { - (byte) 192, (byte) 168, (byte) 1, (byte) 1 - }; - private static final byte[] IPV4_DESTINATION_ADDRESS = { - (byte) 192, (byte) 168, (byte) 1, (byte) 2 - }; - private static final byte[] IPV6_SOURCE_ADDRESS = { - (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 - }; - private static final byte[] IPV6_DESTINATION_ADDRESS = { - (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02 - }; - - private static IPv4 ipv4 = new IPv4(); - private static IPv6 ipv6 = new IPv6(); - private static byte[] bytePacketUDP4 = { - (byte) 0x00, (byte) 0x50, // src port - (byte) 0x00, (byte) 0x60, // dst port - (byte) 0x00, (byte) 0x08, // length - (byte) 0x7b, (byte) 0xda, // checksum - }; - private static byte[] bytePacketUDP6 = { - (byte) 0x00, (byte) 0x50, // src port - (byte) 0x00, (byte) 0x60, // dst port - (byte) 0x00, (byte) 0x08, // length - (byte) 0x02, (byte) 0x2a, // checksum - }; - - private static Deserializer<UDP> deserializer; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - deserializer = UDP.deserializer(); - - ipv4.setSourceAddress(IPv4.toIPv4Address(IPV4_SOURCE_ADDRESS)); - ipv4.setDestinationAddress(IPv4.toIPv4Address(IPV4_DESTINATION_ADDRESS)); - ipv4.setProtocol(IPv4.PROTOCOL_UDP); - - ipv6.setSourceAddress(IPV6_SOURCE_ADDRESS); - ipv6.setDestinationAddress(IPV6_DESTINATION_ADDRESS); - ipv6.setNextHeader(IPv6.PROTOCOL_UDP); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - UDP udp = new UDP(); - udp.setSourcePort(0x50); - udp.setDestinationPort(0x60); - - udp.setParent(ipv4); - assertArrayEquals(bytePacketUDP4, udp.serialize()); - udp.resetChecksum(); - udp.setParent(ipv6); - assertArrayEquals(bytePacketUDP6, udp.serialize()); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(deserializer); - } - - @Test - public void testDeserializeTruncated() throws Exception { - PacketTestUtils.testDeserializeTruncated(deserializer, bytePacketUDP4); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws Exception { - UDP udp = deserializer.deserialize(bytePacketUDP4, 0, bytePacketUDP4.length); - - assertThat(udp.getSourcePort(), is(0x50)); - assertThat(udp.getDestinationPort(), is(0x60)); - assertThat(udp.getLength(), is((short) 8)); - assertThat(udp.getChecksum(), is((short) 0x7bda)); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - UDP udp1 = new UDP(); - udp1.setSourcePort(0x50); - udp1.setDestinationPort(0x60); - - UDP udp2 = new UDP(); - udp2.setSourcePort(0x70); - udp2.setDestinationPort(0x60); - - assertTrue(udp1.equals(udp1)); - assertFalse(udp1.equals(udp2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/VlanIdTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/VlanIdTest.java deleted file mode 100644 index 9ec8ddda..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/VlanIdTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.packet; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import com.google.common.testing.EqualsTester; - -public class VlanIdTest { - - @Test - public void testEquality() { - - VlanId vlan1 = VlanId.vlanId((short) -1); - VlanId vlan2 = VlanId.vlanId((short) 100); - VlanId vlan3 = VlanId.vlanId((short) 100); - - new EqualsTester().addEqualityGroup(VlanId.vlanId(), vlan1) - .addEqualityGroup(vlan2, vlan3) - .addEqualityGroup(VlanId.vlanId((short) 10)); - - } - - @Test - public void basics() { - // purposefully create UNTAGGED VLAN - VlanId vlan1 = VlanId.vlanId((short) 10); - VlanId vlan2 = VlanId.vlanId((short) -1); - - assertEquals("incorrect VLAN value", 10, vlan1.toShort()); - assertEquals("invalid untagged value", VlanId.UNTAGGED, vlan2.toShort()); - } - - @Test(expected = IllegalArgumentException.class) - public void testIllicitVLAN() { - VlanId.vlanId((short) 5000); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/AuthenticationTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/AuthenticationTest.java deleted file mode 100644 index 39ab9104..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/AuthenticationTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.Data; -import org.onlab.packet.Deserializer; -import org.onlab.packet.UDP; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link Authentication}. - */ -public class AuthenticationTest { - private static Data data; - private static UDP udp; - private static byte[] icv = { - (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44 - }; - private static byte[] bytePacket; - - private Deserializer<Authentication> deserializer; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - data = new Data(); - data.setData("testSerialize".getBytes()); - udp = new UDP(); - udp.setPayload(data); - - byte[] bytePayload = udp.serialize(); - byte[] byteHeader = { - (byte) 0x11, (byte) 0x02, (byte) 0x00, (byte) 0x00, - (byte) 0x13, (byte) 0x57, (byte) 0x24, (byte) 0x68, - (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0x00, - (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44 - }; - bytePacket = new byte[byteHeader.length + bytePayload.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); - } - - @Before - public void setUp() { - deserializer = Authentication.deserializer(); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - Authentication auth = new Authentication(); - auth.setNextHeader((byte) 0x11); - auth.setPayloadLength((byte) 0x02); - auth.setSecurityParamIndex(0x13572468); - auth.setSequence(0xffff00); - auth.setIngegrityCheck(icv); - auth.setPayload(udp); - - assertArrayEquals(auth.serialize(), bytePacket); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws Exception { - Authentication auth = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertThat(auth.getNextHeader(), is((byte) 0x11)); - assertThat(auth.getPayloadLength(), is((byte) 0x02)); - assertThat(auth.getSecurityParamIndex(), is(0x13572468)); - assertThat(auth.getSequence(), is(0xffff00)); - assertArrayEquals(auth.getIntegrityCheck(), icv); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - Authentication auth1 = new Authentication(); - auth1.setNextHeader((byte) 0x11); - auth1.setPayloadLength((byte) 0x02); - auth1.setSecurityParamIndex(0x13572468); - auth1.setSequence(0xffff00); - auth1.setIngegrityCheck(icv); - - Authentication auth2 = new Authentication(); - auth2.setNextHeader((byte) 0x11); - auth2.setPayloadLength((byte) 0x02); - auth2.setSecurityParamIndex(0x13572467); - auth2.setSequence(0xffff00); - auth2.setIngegrityCheck(icv); - - assertTrue(auth1.equals(auth1)); - assertFalse(auth1.equals(auth2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/BaseOptionsTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/BaseOptionsTest.java deleted file mode 100644 index bb91e9e7..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/BaseOptionsTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.Data; -import org.onlab.packet.Deserializer; -import org.onlab.packet.IPv6; -import org.onlab.packet.UDP; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link BaseOptions}. - */ -public class BaseOptionsTest { - private static Data data; - private static UDP udp; - private static byte[] options = { - (byte) 0x00, (byte) 0x03, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00 - }; - private static byte[] bytePacket; - - private Deserializer<BaseOptions> deserializer; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - data = new Data(); - data.setData("testSerialize".getBytes()); - udp = new UDP(); - udp.setPayload(data); - - byte[] bytePayload = udp.serialize(); - byte[] byteHeader = { - (byte) 0x11, (byte) 0x00, (byte) 0x00, (byte) 0x03, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00 - }; - bytePacket = new byte[byteHeader.length + bytePayload.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); - } - - @Before - public void setUp() { - deserializer = BaseOptions.deserializer(); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - BaseOptions baseopt = new BaseOptions(); - baseopt.setNextHeader((byte) 0x11); - baseopt.setHeaderExtLength((byte) 0x00); - baseopt.setOptions(options); - baseopt.setPayload(udp); - - assertArrayEquals(baseopt.serialize(), bytePacket); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws Exception { - BaseOptions baseopt = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertThat(baseopt.getNextHeader(), is((byte) 0x11)); - assertThat(baseopt.getHeaderExtLength(), is((byte) 0x00)); - assertArrayEquals(baseopt.getOptions(), options); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - BaseOptions baseopt1 = new BaseOptions(); - baseopt1.setNextHeader((byte) 0x11); - baseopt1.setHeaderExtLength((byte) 0x00); - baseopt1.setOptions(options); - baseopt1.setType(IPv6.PROTOCOL_HOPOPT); - - BaseOptions baseopt2 = new BaseOptions(); - baseopt2.setNextHeader((byte) 0x11); - baseopt2.setHeaderExtLength((byte) 0x00); - baseopt2.setOptions(options); - baseopt1.setType(IPv6.PROTOCOL_DSTOPT); - - assertTrue(baseopt1.equals(baseopt1)); - assertFalse(baseopt1.equals(baseopt2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/DestinationOptionsTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/DestinationOptionsTest.java deleted file mode 100644 index 29dd1266..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/DestinationOptionsTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.junit.Test; -import org.onlab.packet.IPv6; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -/** - * Tests for class {@link DestinationOptions}. - */ -public class DestinationOptionsTest { - /** - * Tests constructor. - */ - @Test - public void testConstructor() { - DestinationOptions dstopt = new DestinationOptions(); - assertThat(dstopt.getType(), is(IPv6.PROTOCOL_DSTOPT)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/EncapSecurityPayloadTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/EncapSecurityPayloadTest.java deleted file mode 100644 index e0e99191..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/EncapSecurityPayloadTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.Data; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; - -import java.util.Arrays; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link EncapSecurityPayload}. - */ -public class EncapSecurityPayloadTest { - private static Data data; - private static byte[] dataByte = new byte[32]; - private static byte[] bytePacket; - - private Deserializer<EncapSecurityPayload> deserializer; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - Arrays.fill(dataByte, (byte) 0xff); - data = new Data().setData(dataByte); - - byte[] bytePayload = data.serialize(); - byte[] byteHeader = { - (byte) 0x13, (byte) 0x57, (byte) 0x24, (byte) 0x68, - (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0x00 - }; - bytePacket = new byte[byteHeader.length + bytePayload.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); - } - - @Before - public void setUp() { - deserializer = EncapSecurityPayload.deserializer(); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - EncapSecurityPayload esp = new EncapSecurityPayload(); - esp.setSecurityParamIndex(0x13572468); - esp.setSequence(0xffff00); - esp.setPayload(data); - - assertArrayEquals(esp.serialize(), bytePacket); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws DeserializationException { - EncapSecurityPayload esp = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertThat(esp.getSecurityParamIndex(), is(0x13572468)); - assertThat(esp.getSequence(), is(0xffff00)); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - EncapSecurityPayload esp1 = new EncapSecurityPayload(); - esp1.setSecurityParamIndex(0x13572468); - esp1.setSequence(0xffff00); - - EncapSecurityPayload esp2 = new EncapSecurityPayload(); - esp2.setSecurityParamIndex(0x13572468); - esp2.setSequence(0xfffff0); - - assertTrue(esp1.equals(esp1)); - assertFalse(esp1.equals(esp2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/FragmentTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/FragmentTest.java deleted file mode 100644 index f2d5e48e..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/FragmentTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.Data; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.UDP; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link Fragment}. - */ -public class FragmentTest { - private static Data data; - private static UDP udp; - private static byte[] bytePacket; - - private Deserializer<Fragment> deserializer; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - data = new Data(); - data.setData("testSerialize".getBytes()); - udp = new UDP(); - udp.setPayload(data); - - byte[] bytePayload = udp.serialize(); - byte[] byteHeader = { - (byte) 0x11, (byte) 0x00, (byte) 0x00, (byte) 0xf9, - (byte) 0x00, (byte) 0x00, (byte) 0x13, (byte) 0x57 - }; - bytePacket = new byte[byteHeader.length + bytePayload.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); - } - - @Before - public void setUp() { - deserializer = Fragment.deserializer(); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - Fragment frag = new Fragment(); - frag.setNextHeader((byte) 0x11); - frag.setFragmentOffset((short) 0x1f); - frag.setMoreFragment((byte) 1); - frag.setIdentification(0x1357); - frag.setPayload(udp); - - assertArrayEquals(frag.serialize(), bytePacket); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws DeserializationException { - Fragment frag = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertThat(frag.getNextHeader(), is((byte) 0x11)); - assertThat(frag.getFragmentOffset(), is((short) 0x1f)); - assertThat(frag.getMoreFragment(), is((byte) 1)); - assertThat(frag.getIdentification(), is(0x1357)); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - Fragment frag1 = new Fragment(); - frag1.setNextHeader((byte) 0x11); - frag1.setFragmentOffset((short) 0x1f); - frag1.setMoreFragment((byte) 1); - frag1.setIdentification(0x1357); - - Fragment frag2 = new Fragment(); - frag2.setNextHeader((byte) 0x11); - frag2.setFragmentOffset((short) 0x1f); - frag2.setMoreFragment((byte) 1); - frag2.setIdentification(0x1358); - - assertTrue(frag1.equals(frag1)); - assertFalse(frag1.equals(frag2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/HopByHopOptionsTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/HopByHopOptionsTest.java deleted file mode 100644 index 1e9be2f6..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/HopByHopOptionsTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.junit.Test; -import org.onlab.packet.IPv6; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -/** - * Tests for class {@link HopByHopOptions}. - */ -public class HopByHopOptionsTest { - /** - * Tests constructor. - */ - @Test - public void testConstructor() { - HopByHopOptions hopopt = new HopByHopOptions(); - assertThat(hopopt.getType(), is(IPv6.PROTOCOL_HOPOPT)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/RoutingTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/RoutingTest.java deleted file mode 100644 index a03bacc9..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ipv6/RoutingTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ipv6; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.Data; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.UDP; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link Routing}. - */ -public class RoutingTest { - private static Data data; - private static UDP udp; - private static byte[] routingData = { - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, - (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce - }; - private static byte[] bytePacket; - - private Deserializer<Routing> deserializer; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - data = new Data(); - data.setData("testSerialize".getBytes()); - udp = new UDP(); - udp.setPayload(data); - - byte[] bytePayload = udp.serialize(); - byte[] byteHeader = { - (byte) 0x11, (byte) 0x02, (byte) 0x00, (byte) 0x03, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, - (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce - }; - bytePacket = new byte[byteHeader.length + bytePayload.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - System.arraycopy(bytePayload, 0, bytePacket, byteHeader.length, bytePayload.length); - } - - @Before - public void setUp() { - deserializer = Routing.deserializer(); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - Routing routing = new Routing(); - routing.setNextHeader((byte) 0x11); - routing.setHeaderExtLength((byte) 0x02); - routing.setRoutingType((byte) 0x00); - routing.setSegmntsLeft((byte) 0x03); - routing.setRoutingData(routingData); - routing.setPayload(udp); - - assertArrayEquals(routing.serialize(), bytePacket); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws DeserializationException { - Routing routing = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertThat(routing.getNextHeader(), is((byte) 0x11)); - assertThat(routing.getHeaderExtLength(), is((byte) 0x02)); - assertThat(routing.getRoutingType(), is((byte) 0x00)); - assertThat(routing.getSegmentsLeft(), is((byte) 0x03)); - assertArrayEquals(routing.getRoutingData(), routingData); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - Routing routing1 = new Routing(); - routing1.setNextHeader((byte) 0x11); - routing1.setHeaderExtLength((byte) 0x02); - routing1.setRoutingType((byte) 0x00); - routing1.setSegmntsLeft((byte) 0x03); - routing1.setRoutingData(routingData); - - Routing routing2 = new Routing(); - routing2.setNextHeader((byte) 0x11); - routing2.setHeaderExtLength((byte) 0x02); - routing2.setRoutingType((byte) 0x00); - routing2.setSegmntsLeft((byte) 0x02); - routing2.setRoutingData(routingData); - - assertTrue(routing1.equals(routing1)); - assertFalse(routing1.equals(routing2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborAdvertisementTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborAdvertisementTest.java deleted file mode 100644 index d537251c..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborAdvertisementTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.MacAddress; -import org.onlab.packet.PacketTestUtils; - -import java.nio.ByteBuffer; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link NeighborAdvertisement}. - */ -public class NeighborAdvertisementTest { - private static final byte[] TARGET_ADDRESS = { - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, - (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce - }; - private static final MacAddress MAC_ADDRESS = - MacAddress.valueOf("11:22:33:44:55:66"); - - private static byte[] bytePacket; - - private Deserializer<NeighborAdvertisement> deserializer - = NeighborAdvertisement.deserializer(); - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - byte[] byteHeader = { - (byte) 0xe0, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, - (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce, - (byte) 0x02, (byte) 0x01, (byte) 0x11, (byte) 0x22, - (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66 - }; - bytePacket = new byte[byteHeader.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - NeighborAdvertisement na = new NeighborAdvertisement(); - na.setRouterFlag((byte) 1); - na.setSolicitedFlag((byte) 1); - na.setOverrideFlag((byte) 1); - na.setTargetAddress(TARGET_ADDRESS); - na.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - assertArrayEquals(na.serialize(), bytePacket); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(NeighborAdvertisement.deserializer()); - } - - @Test - public void testDeserializeTruncated() throws Exception { - // Run the truncation test only on the NeighborAdvertisement header - byte[] naHeader = new byte[NeighborAdvertisement.HEADER_LENGTH]; - ByteBuffer.wrap(bytePacket).get(naHeader); - - PacketTestUtils.testDeserializeTruncated(NeighborAdvertisement.deserializer(), naHeader); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws DeserializationException { - NeighborAdvertisement na = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertThat(na.getRouterFlag(), is((byte) 1)); - assertThat(na.getSolicitedFlag(), is((byte) 1)); - assertThat(na.getOverrideFlag(), is((byte) 1)); - assertArrayEquals(na.getTargetAddress(), TARGET_ADDRESS); - - // Check the option(s) - assertThat(na.getOptions().size(), is(1)); - NeighborDiscoveryOptions.Option option = na.getOptions().get(0); - assertThat(option.type(), - is(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS)); - assertArrayEquals(option.data(), MAC_ADDRESS.toBytes()); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - NeighborAdvertisement na1 = new NeighborAdvertisement(); - na1.setRouterFlag((byte) 1); - na1.setSolicitedFlag((byte) 1); - na1.setOverrideFlag((byte) 1); - na1.setTargetAddress(TARGET_ADDRESS); - na1.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - NeighborAdvertisement na2 = new NeighborAdvertisement(); - na2.setRouterFlag((byte) 1); - na2.setSolicitedFlag((byte) 1); - na2.setOverrideFlag((byte) 0); - na2.setTargetAddress(TARGET_ADDRESS); - na2.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - assertTrue(na1.equals(na1)); - assertFalse(na1.equals(na2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborSolicitationTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborSolicitationTest.java deleted file mode 100644 index 03e57f5e..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborSolicitationTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.MacAddress; -import org.onlab.packet.PacketTestUtils; - -import java.nio.ByteBuffer; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link NeighborSolicitation}. - */ -public class NeighborSolicitationTest { - private static final byte[] TARGET_ADDRESS = { - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, - (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce - }; - private static final byte[] TARGET_ADDRESS2 = { - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xe6, (byte) 0xce, (byte) 0x8f, (byte) 0xff, - (byte) 0xfe, (byte) 0x54, (byte) 0x37, (byte) 0xc8 - }; - private static final MacAddress MAC_ADDRESS = - MacAddress.valueOf("11:22:33:44:55:66"); - - private static byte[] bytePacket; - - private Deserializer<NeighborSolicitation> deserializer - = NeighborSolicitation.deserializer(); - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - byte[] byteHeader = { - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, - (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce, - (byte) 0x02, (byte) 0x01, (byte) 0x11, (byte) 0x22, - (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66 - }; - bytePacket = new byte[byteHeader.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - NeighborSolicitation ns = new NeighborSolicitation(); - ns.setTargetAddress(TARGET_ADDRESS); - ns.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - assertArrayEquals(ns.serialize(), bytePacket); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(NeighborSolicitation.deserializer()); - } - - @Test - public void testDeserializeTruncated() throws Exception { - // Run the truncation test only on the NeighborSolicitation header - byte[] nsHeader = new byte[NeighborSolicitation.HEADER_LENGTH]; - ByteBuffer.wrap(bytePacket).get(nsHeader); - - PacketTestUtils.testDeserializeTruncated(NeighborSolicitation.deserializer(), nsHeader); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws DeserializationException { - NeighborSolicitation ns = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertArrayEquals(ns.getTargetAddress(), TARGET_ADDRESS); - - // Check the option(s) - assertThat(ns.getOptions().size(), is(1)); - NeighborDiscoveryOptions.Option option = ns.getOptions().get(0); - assertThat(option.type(), - is(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS)); - assertArrayEquals(option.data(), MAC_ADDRESS.toBytes()); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - NeighborSolicitation ns1 = new NeighborSolicitation(); - ns1.setTargetAddress(TARGET_ADDRESS); - ns1.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - NeighborSolicitation ns2 = new NeighborSolicitation(); - ns2.setTargetAddress(TARGET_ADDRESS2); - ns2.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - assertTrue(ns1.equals(ns1)); - assertFalse(ns1.equals(ns2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RedirectTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RedirectTest.java deleted file mode 100644 index 31157145..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RedirectTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.MacAddress; -import org.onlab.packet.PacketTestUtils; - -import java.nio.ByteBuffer; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link Redirect}. - */ -public class RedirectTest { - private static final byte[] TARGET_ADDRESS = { - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 - }; - private static final byte[] DESTINATION_ADDRESS = { - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, - (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce - }; - private static final byte[] DESTINATION_ADDRESS2 = { - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xe6, (byte) 0xce, (byte) 0x8f, (byte) 0xff, - (byte) 0xfe, (byte) 0x54, (byte) 0x37, (byte) 0xc8 - }; - private static final MacAddress MAC_ADDRESS = - MacAddress.valueOf("11:22:33:44:55:66"); - - private static byte[] bytePacket; - - private Deserializer<Redirect> deserializer = Redirect.deserializer(); - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - byte[] byteHeader = { - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18, - (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15, - (byte) 0xca, (byte) 0x2a, (byte) 0x14, (byte) 0xff, - (byte) 0xfe, (byte) 0x35, (byte) 0x26, (byte) 0xce, - (byte) 0x02, (byte) 0x01, (byte) 0x11, (byte) 0x22, - (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66 - }; - bytePacket = new byte[byteHeader.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - Redirect rd = new Redirect(); - rd.setTargetAddress(TARGET_ADDRESS); - rd.setDestinationAddress(DESTINATION_ADDRESS); - rd.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - assertArrayEquals(rd.serialize(), bytePacket); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(Redirect.deserializer()); - } - - @Test - public void testDeserializeTruncated() throws Exception { - // Run the truncation test only on the Redirect header - byte[] rdHeader = new byte[Redirect.HEADER_LENGTH]; - ByteBuffer.wrap(bytePacket).get(rdHeader); - - PacketTestUtils.testDeserializeTruncated(Redirect.deserializer(), rdHeader); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws DeserializationException { - Redirect rd = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertArrayEquals(rd.getTargetAddress(), TARGET_ADDRESS); - assertArrayEquals(rd.getDestinationAddress(), DESTINATION_ADDRESS); - - // Check the option(s) - assertThat(rd.getOptions().size(), is(1)); - NeighborDiscoveryOptions.Option option = rd.getOptions().get(0); - assertThat(option.type(), - is(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS)); - assertArrayEquals(option.data(), MAC_ADDRESS.toBytes()); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - Redirect rd1 = new Redirect(); - rd1.setTargetAddress(TARGET_ADDRESS); - rd1.setDestinationAddress(DESTINATION_ADDRESS); - rd1.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - Redirect rd2 = new Redirect(); - rd2.setTargetAddress(TARGET_ADDRESS); - rd2.setDestinationAddress(DESTINATION_ADDRESS2); - rd2.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - assertTrue(rd1.equals(rd1)); - assertFalse(rd1.equals(rd2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RouterAdvertisementTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RouterAdvertisementTest.java deleted file mode 100644 index ede15747..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RouterAdvertisementTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.DeserializationException; -import org.onlab.packet.Deserializer; -import org.onlab.packet.MacAddress; -import org.onlab.packet.PacketTestUtils; - -import java.nio.ByteBuffer; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link RouterAdvertisement}. - */ -public class RouterAdvertisementTest { - private static final MacAddress MAC_ADDRESS = - MacAddress.valueOf("11:22:33:44:55:66"); - - private static byte[] bytePacket; - - private Deserializer<RouterAdvertisement> deserializer - = RouterAdvertisement.deserializer(); - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - byte[] byteHeader = { - (byte) 0x03, (byte) 0xc0, (byte) 0x02, (byte) 0x58, - (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0xe8, - (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0xf4, - (byte) 0x02, (byte) 0x01, (byte) 0x11, (byte) 0x22, - (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66 - }; - bytePacket = new byte[byteHeader.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - RouterAdvertisement ra = new RouterAdvertisement(); - ra.setCurrentHopLimit((byte) 3); - ra.setMFlag((byte) 1); - ra.setOFlag((byte) 1); - ra.setRouterLifetime((short) 0x258); - ra.setReachableTime(0x3e8); - ra.setRetransmitTimer(0x1f4); - ra.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - assertArrayEquals(ra.serialize(), bytePacket); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(RouterAdvertisement.deserializer()); - } - - @Test - public void testDeserializeTruncated() throws Exception { - // Run the truncation test only on the RouterAdvertisement header - byte[] raHeader = new byte[RouterAdvertisement.HEADER_LENGTH]; - ByteBuffer.wrap(bytePacket).get(raHeader); - - PacketTestUtils.testDeserializeTruncated(RouterAdvertisement.deserializer(), raHeader); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws DeserializationException { - RouterAdvertisement ra = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - assertThat(ra.getCurrentHopLimit(), is((byte) 3)); - assertThat(ra.getMFlag(), is((byte) 1)); - assertThat(ra.getOFlag(), is((byte) 1)); - assertThat(ra.getRouterLifetime(), is((short) 0x258)); - assertThat(ra.getReachableTime(), is(0x3e8)); - assertThat(ra.getRetransmitTimer(), is(0x1f4)); - - // Check the option(s) - assertThat(ra.getOptions().size(), is(1)); - NeighborDiscoveryOptions.Option option = ra.getOptions().get(0); - assertThat(option.type(), - is(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS)); - assertArrayEquals(option.data(), MAC_ADDRESS.toBytes()); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - RouterAdvertisement ra1 = new RouterAdvertisement(); - ra1.setCurrentHopLimit((byte) 3); - ra1.setMFlag((byte) 1); - ra1.setOFlag((byte) 1); - ra1.setRouterLifetime((short) 0x258); - ra1.setReachableTime(0x3e8); - ra1.setRetransmitTimer(0x1f4); - ra1.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - RouterAdvertisement ra2 = new RouterAdvertisement(); - ra2.setCurrentHopLimit((byte) 3); - ra2.setMFlag((byte) 0); - ra2.setOFlag((byte) 0); - ra2.setRouterLifetime((short) 0x1f4); - ra2.setReachableTime(0x3e8); - ra2.setRetransmitTimer(0x1f4); - ra2.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS.toBytes()); - - assertTrue(ra1.equals(ra1)); - assertFalse(ra1.equals(ra2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RouterSolicitationTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RouterSolicitationTest.java deleted file mode 100644 index e3b5686c..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/packet/ndp/RouterSolicitationTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.packet.ndp; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.packet.Deserializer; -import org.onlab.packet.MacAddress; -import org.onlab.packet.PacketTestUtils; - -import java.nio.ByteBuffer; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * Tests for class {@link RouterSolicitation}. - */ -public class RouterSolicitationTest { - private static final MacAddress MAC_ADDRESS1 = - MacAddress.valueOf("11:22:33:44:55:66"); - private static final MacAddress MAC_ADDRESS2 = - MacAddress.valueOf("11:22:33:44:55:00"); - - private static byte[] bytePacket; - - private Deserializer<RouterSolicitation> deserializer - = RouterSolicitation.deserializer(); - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - byte[] byteHeader = { - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x02, (byte) 0x01, (byte) 0x11, (byte) 0x22, - (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66 - }; - bytePacket = new byte[byteHeader.length]; - System.arraycopy(byteHeader, 0, bytePacket, 0, byteHeader.length); - } - - /** - * Tests serialize and setters. - */ - @Test - public void testSerialize() { - RouterSolicitation rs = new RouterSolicitation(); - rs.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS1.toBytes()); - - assertArrayEquals(rs.serialize(), bytePacket); - } - - @Test - public void testDeserializeBadInput() throws Exception { - PacketTestUtils.testDeserializeBadInput(RouterSolicitation.deserializer()); - } - - @Test - public void testDeserializeTruncated() throws Exception { - // Run the truncation test only on the RouterSolicitation header - byte[] rsHeader = new byte[RouterSolicitation.HEADER_LENGTH]; - ByteBuffer.wrap(bytePacket).get(rsHeader); - - PacketTestUtils.testDeserializeTruncated(RouterSolicitation.deserializer(), rsHeader); - } - - /** - * Tests deserialize and getters. - */ - @Test - public void testDeserialize() throws Exception { - RouterSolicitation rs = deserializer.deserialize(bytePacket, 0, bytePacket.length); - - // Check the option(s) - assertThat(rs.getOptions().size(), is(1)); - NeighborDiscoveryOptions.Option option = rs.getOptions().get(0); - assertThat(option.type(), - is(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS)); - assertArrayEquals(option.data(), MAC_ADDRESS1.toBytes()); - } - - /** - * Tests comparator. - */ - @Test - public void testEqual() { - RouterSolicitation rs1 = new RouterSolicitation(); - rs1.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS1.toBytes()); - - RouterSolicitation rs2 = new RouterSolicitation(); - rs2.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, - MAC_ADDRESS2.toBytes()); - - assertTrue(rs1.equals(rs1)); - assertFalse(rs1.equals(rs2)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java deleted file mode 100644 index 8a409c3d..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.Test; - -import java.util.List; -import java.util.stream.IntStream; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.onlab.junit.TestTools.assertAfter; - -/** - * Tests the operation of the accumulator. - */ -public class AbstractAccumulatorTest { - - - private final ManuallyAdvancingTimer timer = new ManuallyAdvancingTimer(true); - - private static final int LONG_REAL_TIME_DELAY = 30; - private static final int SHORT_REAL_TIME_DELAY = 5; - - - @Test - public void basics() throws Exception { - TestAccumulator accumulator = new TestAccumulator(); - assertEquals("incorrect timer", timer, accumulator.timer()); - assertEquals("incorrect max events", 5, accumulator.maxItems()); - assertEquals("incorrect max ms", 100, accumulator.maxBatchMillis()); - assertEquals("incorrect idle ms", 70, accumulator.maxIdleMillis()); - } - - @Test - public void eventTrigger() { - TestAccumulator accumulator = new TestAccumulator(); - accumulator.add(new TestItem("a")); - accumulator.add(new TestItem("b")); - accumulator.add(new TestItem("c")); - accumulator.add(new TestItem("d")); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.add(new TestItem("e")); - timer.advanceTimeMillis(20, LONG_REAL_TIME_DELAY); - assertFalse("should have fired", accumulator.batch.isEmpty()); - assertEquals("incorrect batch", "abcde", accumulator.batch); - } - - @Test - public void timeTrigger() { - TestAccumulator accumulator = new TestAccumulator(); - accumulator.add(new TestItem("a")); - timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.add(new TestItem("c")); - timer.advanceTimeMillis(30, SHORT_REAL_TIME_DELAY); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.add(new TestItem("d")); - timer.advanceTimeMillis(10, LONG_REAL_TIME_DELAY); - assertFalse("should have fired", accumulator.batch.isEmpty()); - assertEquals("incorrect batch", "abcd", accumulator.batch); - } - - @Test - public void idleTrigger() { - TestAccumulator accumulator = new TestAccumulator(); - accumulator.add(new TestItem("a")); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(70, LONG_REAL_TIME_DELAY); - assertFalse("should have fired", accumulator.batch.isEmpty()); - assertEquals("incorrect batch", "ab", accumulator.batch); - } - - @Test - public void readyIdleTrigger() { - TestAccumulator accumulator = new TestAccumulator(); - accumulator.ready = false; - accumulator.add(new TestItem("a")); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.add(new TestItem("b")); - timer.advanceTimeMillis(80, SHORT_REAL_TIME_DELAY); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.ready = true; - timer.advanceTimeMillis(80, LONG_REAL_TIME_DELAY); - assertFalse("should have fired", accumulator.batch.isEmpty()); - assertEquals("incorrect batch", "ab", accumulator.batch); - } - - @Test - public void readyLongTrigger() { - TestAccumulator accumulator = new TestAccumulator(); - accumulator.ready = false; - timer.advanceTimeMillis(120, SHORT_REAL_TIME_DELAY); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.add(new TestItem("a")); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.ready = true; - timer.advanceTimeMillis(120, LONG_REAL_TIME_DELAY); - assertFalse("should have fired", accumulator.batch.isEmpty()); - assertEquals("incorrect batch", "a", accumulator.batch); - } - - @Test - public void readyMaxTrigger() { - TestAccumulator accumulator = new TestAccumulator(); - accumulator.ready = false; - accumulator.add(new TestItem("a")); - accumulator.add(new TestItem("b")); - accumulator.add(new TestItem("c")); - accumulator.add(new TestItem("d")); - accumulator.add(new TestItem("e")); - accumulator.add(new TestItem("f")); - assertTrue("should not have fired yet", accumulator.batch.isEmpty()); - accumulator.ready = true; - accumulator.add(new TestItem("g")); - timer.advanceTimeMillis(10, LONG_REAL_TIME_DELAY); - assertFalse("should have fired", accumulator.batch.isEmpty()); - assertEquals("incorrect batch", "abcdefg", accumulator.batch); - } - - @Test - public void stormTest() { - TestAccumulator accumulator = new TestAccumulator(); - IntStream.range(0, 1000).forEach(i -> accumulator.add(new TestItem("#" + i))); - timer.advanceTimeMillis(1); - assertAfter(100, () -> assertEquals("wrong item count", 1000, accumulator.itemCount)); - assertEquals("wrong batch count", 200, accumulator.batchCount); - } - - private class TestItem { - private final String s; - - public TestItem(String s) { - this.s = s; - } - } - - private class TestAccumulator extends AbstractAccumulator<TestItem> { - - String batch = ""; - boolean ready = true; - int batchCount = 0; - int itemCount = 0; - - protected TestAccumulator() { - super(timer, 5, 100, 70); - } - - @Override - public void processItems(List<TestItem> items) { - batchCount++; - itemCount += items.size(); - for (TestItem item : items) { - batch += item.s; - } - } - - @Override - public boolean isReady() { - return ready; - } - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BandwidthTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BandwidthTest.java deleted file mode 100644 index a3baf06c..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BandwidthTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.lessThan; -import static org.junit.Assert.assertThat; - -/** - * Unit tests for Bandwidth. - */ -public class BandwidthTest { - - private final Bandwidth small = Bandwidth.kbps(100.0); - private final Bandwidth large = Bandwidth.mbps(1.0); - - /** - * Tests equality of Bandwidth instances. - */ - @Test - public void testEquality() { - new EqualsTester() - .addEqualityGroup(Bandwidth.kbps(1000.0), Bandwidth.kbps(1000.0), Bandwidth.mbps(1.0)) - .addEqualityGroup(Bandwidth.gbps(1.0)) - .testEquals(); - } - - /** - * Tests add operation of two Bandwidths. - */ - @Test - public void testAdd() { - Bandwidth expected = Bandwidth.kbps(1100.0); - - assertThat(small.add(large), is(expected)); - } - - /** - * Tests subtract operation of two Bandwidths. - */ - @Test - public void testSubtract() { - Bandwidth expected = Bandwidth.kbps(900.0); - - assertThat(large.subtract(small), is(expected)); - } - - /** - * Tests if the first object is less than the second object. - */ - @Test - public void testLessThan() { - assertThat(small, is(lessThan(large))); - assertThat(small.isLessThan(large), is(true)); - } - - /** - * Tests if the first object is greater than the second object. - */ - @Test - public void testGreaterThan() { - assertThat(large, is(greaterThan(small))); - assertThat(large.isGreaterThan(small), is(true)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BlockingBooleanTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BlockingBooleanTest.java deleted file mode 100644 index 2d8b688e..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BlockingBooleanTest.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.apache.commons.lang.mutable.MutableBoolean; -import org.junit.Ignore; -import org.junit.Test; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import static org.junit.Assert.*; - -/** - * Tests of the BlockingBoolean utility. - */ -public class BlockingBooleanTest { - - private static final int TIMEOUT = 100; //ms - - @Test - public void basics() { - BlockingBoolean b = new BlockingBoolean(false); - assertEquals(false, b.get()); - b.set(true); - assertEquals(true, b.get()); - b.set(true); - assertEquals(true, b.get()); - b.set(false); - assertEquals(false, b.get()); - } - - private void waitChange(boolean value, int numThreads) { - BlockingBoolean b = new BlockingBoolean(!value); - - CountDownLatch latch = new CountDownLatch(numThreads); - ExecutorService exec = Executors.newFixedThreadPool(numThreads); - for (int i = 0; i < numThreads; i++) { - exec.submit(() -> { - try { - b.await(value); - latch.countDown(); - } catch (InterruptedException e) { - fail(); - } - }); - } - b.set(value); - try { - assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(); - } - exec.shutdown(); - } - - @Test - public void waitTrueChange() { - waitChange(true, 4); - } - - @Test - public void waitFalseChange() { - waitChange(false, 4); - } - - @Test - public void waitSame() { - BlockingBoolean b = new BlockingBoolean(true); - - CountDownLatch latch = new CountDownLatch(1); - ExecutorService exec = Executors.newSingleThreadExecutor(); - exec.submit(() -> { - try { - b.await(true); - latch.countDown(); - } catch (InterruptedException e) { - fail(); - } - }); - try { - assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(); - } - exec.shutdown(); - } - - @Test - public void someWait() { - BlockingBoolean b = new BlockingBoolean(false); - - int numThreads = 4; - CountDownLatch sameLatch = new CountDownLatch(numThreads / 2); - CountDownLatch waitLatch = new CountDownLatch(numThreads / 2); - - ExecutorService exec = Executors.newFixedThreadPool(numThreads); - for (int i = 0; i < numThreads; i++) { - final boolean value = (i % 2 == 1); - exec.submit(() -> { - try { - b.await(value); - if (value) { - waitLatch.countDown(); - } else { - sameLatch.countDown(); - } - } catch (InterruptedException e) { - fail(); - } - }); - } - try { - assertTrue(sameLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)); - assertEquals(waitLatch.getCount(), numThreads / 2); - } catch (InterruptedException e) { - fail(); - } - b.set(true); - try { - assertTrue(waitLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(); - } - exec.shutdown(); - } - - @Test - public void waitTimeout() { - BlockingBoolean b = new BlockingBoolean(true); - - CountDownLatch latch = new CountDownLatch(1); - ExecutorService exec = Executors.newSingleThreadExecutor(); - exec.submit(() -> { - try { - if (!b.await(false, 1, TimeUnit.NANOSECONDS)) { - latch.countDown(); - } else { - fail(); - } - } catch (InterruptedException e) { - fail(); - } - }); - try { - assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(); - } - exec.shutdown(); - - } - - @Test - @Ignore - public void samePerf() { - int iters = 10_000; - - BlockingBoolean b1 = new BlockingBoolean(false); - long t1 = System.nanoTime(); - for (int i = 0; i < iters; i++) { - b1.set(false); - } - long t2 = System.nanoTime(); - MutableBoolean b2 = new MutableBoolean(false); - for (int i = 0; i < iters; i++) { - b2.setValue(false); - } - long t3 = System.nanoTime(); - System.out.println((t2 - t1) + " " + (t3 - t2) + " " + ((t2 - t1) <= (t3 - t2))); - } - - @Test - @Ignore - public void changePerf() { - int iters = 10_000; - - BlockingBoolean b1 = new BlockingBoolean(false); - boolean v = true; - long t1 = System.nanoTime(); - for (int i = 0; i < iters; i++) { - b1.set(v); - v = !v; - } - long t2 = System.nanoTime(); - MutableBoolean b2 = new MutableBoolean(false); - for (int i = 0; i < iters; i++) { - b2.setValue(v); - v = !v; - } - long t3 = System.nanoTime(); - System.out.println((t2 - t1) + " " + (t3 - t2) + " " + ((t2 - t1) <= (t3 - t2))); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BoundedThreadPoolTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BoundedThreadPoolTest.java deleted file mode 100644 index c6132de1..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BoundedThreadPoolTest.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.collect.Lists; -import org.junit.Test; - -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.junit.Assert.*; -import static org.onlab.util.BoundedThreadPool.*; -import static org.onlab.util.Tools.namedThreads; - -/** - * Test of BoundedThreadPool. - */ -public final class BoundedThreadPoolTest { - - @Test - public void simpleJob() { - final Thread myThread = Thread.currentThread(); - final AtomicBoolean sameThread = new AtomicBoolean(true); - final CountDownLatch latch = new CountDownLatch(1); - - BoundedThreadPool exec = newSingleThreadExecutor(namedThreads("test")); - exec.submit(() -> { - sameThread.set(myThread.equals(Thread.currentThread())); - latch.countDown(); - }); - - try { - assertTrue("Job not run", latch.await(100, TimeUnit.MILLISECONDS)); - assertFalse("Runnable used caller thread", sameThread.get()); - } catch (InterruptedException e) { - fail(); - } finally { - exec.shutdown(); - } - - // TODO perhaps move to tearDown - try { - assertTrue(exec.awaitTermination(1, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - fail(); - } - } - - private List<CountDownLatch> fillExecutor(BoundedThreadPool exec) { - int numThreads = exec.getMaximumPoolSize(); - List<CountDownLatch> latches = Lists.newArrayList(); - final CountDownLatch started = new CountDownLatch(numThreads); - List<CountDownLatch> finished = Lists.newArrayList(); - - // seed the executor's threads - for (int i = 0; i < numThreads; i++) { - final CountDownLatch latch = new CountDownLatch(1); - final CountDownLatch fin = new CountDownLatch(1); - latches.add(latch); - finished.add(fin); - exec.submit(() -> { - try { - started.countDown(); - latch.await(); - fin.countDown(); - } catch (InterruptedException e) { - fail(); - } - }); - } - try { - assertTrue(started.await(100, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(); - } - // fill the queue - CountDownLatch startedBlocked = new CountDownLatch(1); - while (exec.getQueue().remainingCapacity() > 0) { - final CountDownLatch latch = new CountDownLatch(1); - latches.add(latch); - exec.submit(() -> { - try { - startedBlocked.countDown(); - latch.await(); - } catch (InterruptedException e) { - fail(); - } - }); - } - - latches.remove(0).countDown(); // release one of the executors - // ... we need to do this because load is recomputed when jobs are taken - // Note: For this to work, 1 / numThreads must be less than the load threshold (0.2) - - // verify that the old job has terminated - try { - assertTrue("Job didn't finish", - finished.remove(0).await(100, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(); - } - - // verify that a previously blocked thread has started - try { - assertTrue(startedBlocked.await(10, TimeUnit.MILLISECONDS)); - } catch (InterruptedException e) { - fail(); - } - - - // add another job to fill the queue - final CountDownLatch latch = new CountDownLatch(1); - latches.add(latch); - exec.submit(() -> { - try { - latch.await(); - } catch (InterruptedException e) { - fail(); - } - }); - assertEquals(exec.getQueue().size(), maxQueueSize); - - return latches; - } - - @Test - public void releaseOneThread() { - maxQueueSize = 10; - BoundedThreadPool exec = newFixedThreadPool(4, namedThreads("test")); - List<CountDownLatch> latches = fillExecutor(exec); - - CountDownLatch myLatch = new CountDownLatch(1); - ExecutorService myExec = Executors.newSingleThreadExecutor(); - Future<Thread> expected = myExec.submit(Thread::currentThread); - - assertEquals(exec.getQueue().size(), maxQueueSize); - long start = System.nanoTime(); - Future<Thread> actual = myExec.submit(() -> { - return exec.submit(() -> { - myLatch.countDown(); - return Thread.currentThread(); - }).get(); - }); - - try { - assertFalse("Thread should still be blocked", - myLatch.await(10, TimeUnit.MILLISECONDS)); - - latches.remove(0).countDown(); // release the first thread - assertFalse("Thread should still be blocked", - myLatch.await(10, TimeUnit.MILLISECONDS)); - latches.remove(0).countDown(); // release the second thread - - assertTrue("Thread should be unblocked", - myLatch.await(10, TimeUnit.MILLISECONDS)); - long delta = System.nanoTime() - start; - double load = exec.getQueue().size() / (double) maxQueueSize; - assertTrue("Load is greater than threshold", load <= 0.8); - assertTrue("Load is less than threshold", load >= 0.6); - assertEquals("Work done on wrong thread", expected.get(), actual.get()); - assertTrue("Took more than one second", delta < Math.pow(10, 9)); - } catch (InterruptedException | ExecutionException e) { - fail(); - } finally { - latches.forEach(CountDownLatch::countDown); - exec.shutdown(); - } - - // TODO perhaps move to tearDown - try { - assertTrue(exec.awaitTermination(1, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - fail(); - } - - } - - @Test - public void highLoadTimeout() { - maxQueueSize = 10; - BoundedThreadPool exec = newFixedThreadPool(2, namedThreads("test")); - List<CountDownLatch> latches = fillExecutor(exec); - - // true if the job is executed and it is done on the test thread - final AtomicBoolean sameThread = new AtomicBoolean(false); - final Thread myThread = Thread.currentThread(); - long start = System.nanoTime(); - exec.submit(() -> { - sameThread.set(myThread.equals(Thread.currentThread())); - }); - - long delta = System.nanoTime() - start; - assertEquals(maxQueueSize, exec.getQueue().size()); - assertTrue("Work done on wrong thread (or didn't happen)", sameThread.get()); - assertTrue("Took less than one second. Actual: " + delta / 1_000_000.0 + "ms", - delta > Math.pow(10, 9)); - assertTrue("Took more than two seconds", delta < 2 * Math.pow(10, 9)); - latches.forEach(CountDownLatch::countDown); - exec.shutdown(); - - // TODO perhaps move to tearDown - try { - assertTrue(exec.awaitTermination(1, TimeUnit.SECONDS)); - } catch (InterruptedException e) { - fail(); - } - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ByteArraySizeHashPrinterTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ByteArraySizeHashPrinterTest.java deleted file mode 100644 index e3a5e945..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ByteArraySizeHashPrinterTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.util; - -import static org.junit.Assert.*; - -import java.util.Arrays; - -import org.junit.Test; - -/** - * Test cases for byte[] pretty printer. - */ -public class ByteArraySizeHashPrinterTest { - - /** - * Test method for {@link org.onlab.util.ByteArraySizeHashPrinter#toString()}. - */ - @Test - public void testToStringNull() { - final byte[] none = null; - - assertEquals("byte[]{null}", String.valueOf(ByteArraySizeHashPrinter.of(none))); - assertNull(ByteArraySizeHashPrinter.orNull(none)); - } - - /** - * Test method for {@link org.onlab.util.ByteArraySizeHashPrinter#toString()}. - */ - @Test - public void testToString() { - final byte[] some = new byte[] {2, 5, 0, 1 }; - final String expected = "byte[]{length=" + some.length + ", hash=" + Arrays.hashCode(some) + "}"; - - assertEquals(expected, String.valueOf(ByteArraySizeHashPrinter.of(some))); - assertNotNull(ByteArraySizeHashPrinter.orNull(some)); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/CounterTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/CounterTest.java deleted file mode 100644 index d30e1b59..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/CounterTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.onlab.junit.TestTools.delay; - -/** - * Tests of the Counter utility. - */ -public class CounterTest { - - @Test - public void basics() { - Counter tt = new Counter(); - assertEquals("incorrect number of bytes", 0L, tt.total()); - assertEquals("incorrect throughput", 0.0, tt.throughput(), 0.0001); - tt.add(1234567890L); - assertEquals("incorrect number of bytes", 1234567890L, tt.total()); - assertTrue("incorrect throughput", 1234567890.0 < tt.throughput()); - delay(1500); - tt.add(1L); - assertEquals("incorrect number of bytes", 1234567891L, tt.total()); - assertTrue("incorrect throughput", 1234567891.0 > tt.throughput()); - tt.reset(); - assertEquals("incorrect number of bytes", 0L, tt.total()); - assertEquals("incorrect throughput", 0.0, tt.throughput(), 0.0001); - } - - @Test - public void freeze() { - Counter tt = new Counter(); - tt.add(123L); - assertEquals("incorrect number of bytes", 123L, tt.total()); - delay(1000); - tt.freeze(); - tt.add(123L); - assertEquals("incorrect number of bytes", 123L, tt.total()); - - double d = tt.duration(); - double t = tt.throughput(); - assertEquals("incorrect duration", d, tt.duration(), 0.0001); - assertEquals("incorrect throughput", t, tt.throughput(), 0.0001); - assertEquals("incorrect number of bytes", 123L, tt.total()); - } - - @Test - public void reset() { - Counter tt = new Counter(); - tt.add(123L); - assertEquals("incorrect number of bytes", 123L, tt.total()); - - double d = tt.duration(); - double t = tt.throughput(); - assertEquals("incorrect duration", d, tt.duration(), 0.0001); - assertEquals("incorrect throughput", t, tt.throughput(), 0.0001); - assertEquals("incorrect number of bytes", 123L, tt.total()); - - tt.reset(); - assertEquals("incorrect throughput", 0.0, tt.throughput(), 0.0001); - assertEquals("incorrect number of bytes", 0, tt.total()); - } - - @Test - public void syntheticTracker() { - Counter tt = new Counter(5000, 1000, 6000); - assertEquals("incorrect duration", 1, tt.duration(), 0.1); - assertEquals("incorrect throughput", 1000, tt.throughput(), 1.0); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/DefaultHashMapTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/DefaultHashMapTest.java deleted file mode 100644 index db6b5fb7..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/DefaultHashMapTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Unit tests for {@link DefaultHashMap}. - */ -public class DefaultHashMapTest { - - private static final String ONE = "one"; - private static final String TWO = "two"; - private static final String THREE = "three"; - private static final String FOUR = "four"; - - private static final String ALPHA = "Alpha"; - private static final String BETA = "Beta"; - private static final String OMEGA = "Omega"; - - private DefaultHashMap<String, Integer> map; - private DefaultHashMap<String, String> chartis; - - private void loadMap() { - map.put(ONE, 1); - map.put(TWO, 2); - } - - private void fortioCharti() { - chartis.put(ONE, ALPHA); - chartis.put(TWO, BETA); - } - - @Test - public void nullDefaultIsAllowed() { - // but makes this class behave no different than HashMap - map = new DefaultHashMap<>(null); - loadMap(); - assertEquals("missing 1", 1, (int) map.get(ONE)); - assertEquals("missing 2", 2, (int) map.get(TWO)); - assertEquals("three?", null, map.get(THREE)); - assertEquals("four?", null, map.get(FOUR)); - } - - @Test - public void defaultToFive() { - map = new DefaultHashMap<>(5); - loadMap(); - assertEquals("missing 1", 1, (int) map.get(ONE)); - assertEquals("missing 2", 2, (int) map.get(TWO)); - assertEquals("three?", 5, (int) map.get(THREE)); - assertEquals("four?", 5, (int) map.get(FOUR)); - } - - @Test - public void defaultToOmega() { - chartis = new DefaultHashMap<>(OMEGA); - fortioCharti(); - assertEquals("missing 1", ALPHA, chartis.get(ONE)); - assertEquals("missing 2", BETA, chartis.get(TWO)); - assertEquals("three?", OMEGA, chartis.get(THREE)); - assertEquals("four?", OMEGA, chartis.get(FOUR)); - } - -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/FrequencyTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/FrequencyTest.java deleted file mode 100644 index 727c0f73..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/FrequencyTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; -import org.onlab.junit.ImmutableClassChecker; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.lessThan; - -public class FrequencyTest { - - private final Frequency frequency1 = Frequency.ofMHz(1000); - private final Frequency sameFrequency1 = Frequency.ofMHz(1000); - private final Frequency frequency2 = Frequency.ofGHz(1000); - private final Frequency sameFrequency2 = Frequency.ofGHz(1000); - private final Frequency moreSameFrequency2 = Frequency.ofTHz(1); - private final Frequency frequency3 = Frequency.ofTHz(193.1); - private final Frequency sameFrequency3 = Frequency.ofGHz(193100); - - /** - * Tests immutability of Frequency. - */ - @Test - public void testImmutability() { - ImmutableClassChecker.assertThatClassIsImmutable(Frequency.class); - } - - /** - * Tests equality of Frequency instances. - */ - @Test - public void testEquality() { - new EqualsTester() - .addEqualityGroup(frequency1, sameFrequency1) - .addEqualityGroup(frequency2, sameFrequency2, moreSameFrequency2) - .addEqualityGroup(frequency3, sameFrequency3) - .testEquals(); - } - - /** - * Tests the first object is less than the second object. - */ - @Test - public void testLessThan() { - assertThat(frequency1, is(lessThan(frequency2))); - assertThat(frequency1.isLessThan(frequency2), is(true)); - } - - @Test - public void testGreaterThan() { - assertThat(frequency2, is(greaterThan(frequency1))); - assertThat(frequency2.isGreaterThan(frequency1), is(true)); - } - - /** - * Tests add operation of two Frequencies. - */ - @Test - public void testAdd() { - Frequency low = Frequency.ofMHz(100); - Frequency high = Frequency.ofGHz(1); - Frequency expected = Frequency.ofMHz(1100); - - assertThat(low.add(high), is(expected)); - } - - /** - * Tests subtract operation of two Frequencies. - */ - @Test - public void testSubtract() { - Frequency high = Frequency.ofGHz(1); - Frequency low = Frequency.ofMHz(100); - Frequency expected = Frequency.ofMHz(900); - - assertThat(high.subtract(low), is(expected)); - } - - /** - * Tests multiply operation of Frequency. - */ - @Test - public void testMultiply() { - Frequency frequency = Frequency.ofMHz(1000); - long factor = 5; - Frequency expected = Frequency.ofGHz(5); - - assertThat(frequency.multiply(5), is(expected)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GeoLocationTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GeoLocationTest.java deleted file mode 100644 index a497bcc4..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GeoLocationTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Test suite of the geo location. - */ -public class GeoLocationTest { - - @Test - public void basics() { - GeoLocation nLoc = new GeoLocation(40.7127, -74.0059); - GeoLocation wLoc = new GeoLocation(38.9047, -77.0164); - - assertEquals("incorrect latitude", 40.7127, nLoc.latitude(), 0.0001); - assertEquals("incorrect longitude", -74.00598, nLoc.longitude(), 0.0001); - assertEquals("incorrect distance", 326.74, nLoc.kilometersTo(wLoc), 0.01); - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GroupedThreadFactoryTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GroupedThreadFactoryTest.java deleted file mode 100644 index 5be1cda4..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GroupedThreadFactoryTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.Test; -import org.onlab.junit.TestTools; - -import static org.junit.Assert.*; - -/** - * Tests of the group thread factory. - */ -public class GroupedThreadFactoryTest { - - @Test - public void basics() { - GroupedThreadFactory a = GroupedThreadFactory.groupedThreadFactory("foo"); - GroupedThreadFactory b = GroupedThreadFactory.groupedThreadFactory("foo"); - assertSame("factories should be same", a, b); - - assertTrue("wrong toString", a.toString().contains("foo")); - Thread t = a.newThread(() -> TestTools.print("yo")); - assertSame("wrong group", a.threadGroup(), t.getThreadGroup()); - } - - @Test - public void hierarchical() { - GroupedThreadFactory a = GroupedThreadFactory.groupedThreadFactory("foo/bar"); - GroupedThreadFactory b = GroupedThreadFactory.groupedThreadFactory("foo/goo"); - GroupedThreadFactory p = GroupedThreadFactory.groupedThreadFactory("foo"); - - assertSame("groups should be same", p.threadGroup(), a.threadGroup().getParent()); - assertSame("groups should be same", p.threadGroup(), b.threadGroup().getParent()); - - assertEquals("wrong name", "foo/bar", a.threadGroup().getName()); - assertEquals("wrong name", "foo/goo", b.threadGroup().getName()); - assertEquals("wrong name", "foo", p.threadGroup().getName()); - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/HexStringTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/HexStringTest.java deleted file mode 100644 index f4aadd15..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/HexStringTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.Test; - -import com.esotericsoftware.minlog.Log; - -import junit.framework.TestCase; - -import static org.junit.Assert.fail; - -/** - * Test of the Hexstring. - * - */ - -public class HexStringTest { - - @Test - public void testMarshalling() throws Exception { - String dpidStr = "00:00:00:23:20:2d:16:71"; - long dpid = HexString.toLong(dpidStr); - String testStr = HexString.toHexString(dpid); - TestCase.assertEquals(dpidStr, testStr); - } - - @Test - public void testToLong() { - String dpidStr = "3e:1f:01:fc:72:8c:63:31"; - long valid = 0x3e1f01fc728c6331L; - long testLong = HexString.toLong(dpidStr); - TestCase.assertEquals(valid, testLong); - } - - @Test - public void testToLongMsb() { - String dpidStr = "ca:7c:5e:d1:64:7a:95:9b"; - long valid = -3856102927509056101L; - long testLong = HexString.toLong(dpidStr); - TestCase.assertEquals(valid, testLong); - } - - @Test - public void testToLongError() { - String dpidStr = "09:08:07:06:05:04:03:02:01"; - try { - HexString.toLong(dpidStr); - fail("HexString.toLong() should have thrown a NumberFormatException"); - } catch (NumberFormatException expected) { - Log.info("HexString.toLong() have thrown a NumberFormatException"); - } - } - - @Test - public void testToStringBytes() { - byte[] dpid = {0, 0, 0, 0, 0, 0, 0, -1 }; - String valid = "00:00:00:00:00:00:00:ff"; - String testString = HexString.toHexString(dpid); - TestCase.assertEquals(valid, testString); - } - - @Test - public void testFromHexStringError() { - String invalidStr = "00:00:00:00:00:00:ffff"; - try { - HexString.fromHexString(invalidStr); - fail("HexString.fromHexString() should have thrown a NumberFormatException"); - } catch (NumberFormatException expected) { - Log.info("HexString.toLong() have thrown a NumberFormatException"); - } - } -} - diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java deleted file mode 100644 index 8fb008e8..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimer.java +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.collect.Lists; -import org.onlab.junit.TestUtils; -import org.slf4j.Logger; - -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.TimerTask; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.onlab.junit.TestTools.delay; -import static org.slf4j.LoggerFactory.getLogger; - - -/** - * Provides manually scheduled timer utility. All schedulable methods are subject to overflow (you can set a period of - * max long). Additionally if a skip skips a period of time greater than one period for a periodic task that task will - * only be executed once for that skip and scheduled it's period after the last execution. - */ -public class ManuallyAdvancingTimer extends java.util.Timer { - - /* States whether or not the static values from timer task have been set ensures population will only occur once.*/ - private boolean staticsPopulated = false; - - /* Virgin value from timer task */ - private int virginState; - - /* Scheduled value from timer task */ - private int scheduledState; - - /* Executed value from timer task */ - private int executedState; - - /* Cancelled value from timer task */ - private int cancelledState; - - private final Logger logger = getLogger(getClass()); - - /* Service for executing timer tasks */ - private final ExecutorService executorService = Executors.newSingleThreadExecutor(); - - /* Internal time representation independent of system time, manually advanced */ - private final TimerKeeper timerKeeper = new TimerKeeper(); - - /* Data structure for tracking tasks */ - private final TaskQueue queue = new TaskQueue(); - - /* Whether execution should execute on the executor thread or the calling thread. */ - private final boolean runLocally; - - public ManuallyAdvancingTimer(boolean runLocally) { - this.runLocally = runLocally; - } - - - @Override - public void schedule(TimerTask task, long delay) { - if (!staticsPopulated) { - populateStatics(task); - } - if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay : - timerKeeper.currentTimeInMillis() - delay, 0)) { - logger.error("Failed to submit task"); - } - } - - @Override - public void schedule(TimerTask task, Date time) { - if (!staticsPopulated) { - populateStatics(task); - } - if (!submitTask(task, time.getTime(), 0)) { - logger.error("Failed to submit task"); - } - } - - @Override - public void schedule(TimerTask task, long delay, long period) { - if (!staticsPopulated) { - populateStatics(task); - } - if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay : - timerKeeper.currentTimeInMillis() - delay, period)) { - logger.error("Failed to submit task"); - } - } - - @Override - public void schedule(TimerTask task, Date firstTime, long period) { - if (!staticsPopulated) { - populateStatics(task); - } - if (!submitTask(task, firstTime.getTime(), period)) { - logger.error("Failed to submit task"); - } - } - - /*################################################WARNING################################################*/ - /* Schedule at fixed rate methods do not work exactly as in the java timer. They are clones of the periodic - *scheduling methods. */ - @Override - public void scheduleAtFixedRate(TimerTask task, long delay, long period) { - if (!staticsPopulated) { - populateStatics(task); - } - if (!submitTask(task, delay > 0 ? timerKeeper.currentTimeInMillis() + delay : - timerKeeper.currentTimeInMillis() - delay, period)) { - logger.error("Failed to submit task"); - } - } - - @Override - public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) { - if (!staticsPopulated) { - populateStatics(task); - } - if (!submitTask(task, firstTime.getTime(), period)) { - logger.error("Failed to submit task"); - } - } - - @Override - public void cancel() { - executorService.shutdown(); - queue.clear(); - } - - @Override - public int purge() { - return queue.removeCancelled(); - } - - /** - * Returns the virtual current time in millis. - * - * @return long representing simulated current time. - */ - public long currentTimeInMillis() { - return timerKeeper.currentTimeInMillis(); - } - - /** - * Returns the new simulated current time in millis after advancing the absolute value of millis to advance. - * Triggers event execution of all events scheduled for execution at times up to and including the returned time. - * Passing in the number zero has no effect. - * - * @param millisToAdvance the number of millis to advance. - * @return a long representing the current simulated time in millis - */ - public long advanceTimeMillis(long millisToAdvance) { - return timerKeeper.advanceTimeMillis(millisToAdvance); - } - - /** - * Advances the virtual time a certain number of millis triggers execution delays a certain amount to - * allow time for execution. If runLocally is true then all real time delays are ignored. - * - * @param virtualTimeAdvance the time to be advances in millis of simulated time. - * @param realTimeDelay the time to delay in real time to allow for processing. - */ - public void advanceTimeMillis(long virtualTimeAdvance, int realTimeDelay) { - timerKeeper.advanceTimeMillis(virtualTimeAdvance); - if (!runLocally) { - delay(realTimeDelay); - } - } - - /** - * Sets up the task and submits it to the queue. - * - * @param task the task to be added to the queue - * @param runtime the first runtime of the task - * @param period the period between runs thereafter - * @return returns true if the task was successfully submitted, false otherwise - */ - private boolean submitTask(TimerTask task, long runtime, long period) { - checkNotNull(task); - try { - TestUtils.setField(task, "state", scheduledState); - TestUtils.setField(task, "nextExecutionTime", runtime); - TestUtils.setField(task, "period", period); - } catch (TestUtils.TestUtilsException e) { - e.printStackTrace(); - return false; - } - queue.insertOrdered(task); - return true; - } - - /** - * Executes the given task (only if it is in the scheduled state) and proceeds to reschedule it or mark it as - * executed. Does not remove from the queue (this must be done outside). - * - * @param task the timer task to be executed - */ - private boolean executeTask(TimerTask task) { - checkNotNull(task); - int currentState; - try { - currentState = TestUtils.getField(task, "state"); - } catch (TestUtils.TestUtilsException e) { - logger.error("Could not get state of task."); - e.printStackTrace(); - return false; - } - //If cancelled or already executed stop here. - if (currentState == executedState || currentState == cancelledState) { - return false; - } else if (currentState == virginState) { - logger.error("Task was set for execution without being scheduled."); - return false; - } else if (currentState == scheduledState) { - long period; - - try { - period = TestUtils.getField(task, "period"); - } catch (TestUtils.TestUtilsException e) { - logger.error("Could not read period of task."); - e.printStackTrace(); - return false; - } - //Period of zero means one time execution. - if (period == 0) { - try { - TestUtils.setField(task, "state", executedState); - } catch (TestUtils.TestUtilsException e) { - logger.error("Could not set executed state."); - e.printStackTrace(); - return false; - } - if (runLocally) { - task.run(); - } else { - executorService.execute(task); - } - return true; - } else { - //Calculate next execution time, using absolute value of period - long nextTime = (period > 0) ? (timerKeeper.currentTimeInMillis() + period) : - (timerKeeper.currentTimeInMillis() - period); - try { - TestUtils.setField(task, "nextExecutionTime", nextTime); - } catch (TestUtils.TestUtilsException e) { - logger.error("Could not set next execution time."); - e.printStackTrace(); - return false; - } - //Schedule next execution - queue.insertOrdered(task); - if (runLocally) { - task.run(); - } else { - executorService.execute(task); - } - return true; - } - } - logger.error("State property of {} is in an illegal state and did not execute.", task); - return false; - } - - /** - * Executes all tasks in the queue scheduled for execution up to and including the current time. - * - * @return the total number of tasks run, -1 if failure - */ - private int executeEventsUpToPresent() { - int totalRun = 0; - if (queue.isEmpty()) { - return -1; - } - TimerTask currTask = queue.peek(); - long currExecTime; - try { - currExecTime = TestUtils.getField(currTask, "nextExecutionTime"); - } catch (TestUtils.TestUtilsException e) { - e.printStackTrace(); - throw new RuntimeException("Could not get nextExecutionTime"); - } - while (currExecTime <= timerKeeper.currentTimeInMillis()) { - if (executeTask(queue.pop())) { - totalRun++; - } - if (queue.isEmpty()) { - break; - } - currTask = queue.peek(); - try { - currExecTime = TestUtils.getField(currTask, "nextExecutionTime"); - } catch (TestUtils.TestUtilsException e) { - e.printStackTrace(); - throw new RuntimeException("Could not get nextExecutionTime"); - } - } - return totalRun; - } - - /** - * Populates the static fields from timer task. Should only be called once. - */ - private void populateStatics(TimerTask task) { - try { - virginState = TestUtils.getField(task, "VIRGIN"); - scheduledState = TestUtils.getField(task, "SCHEDULED"); - executedState = TestUtils.getField(task, "EXECUTED"); - cancelledState = TestUtils.getField(task, "CANCELLED"); - staticsPopulated = true; - } catch (TestUtils.TestUtilsException e) { - e.printStackTrace(); - } - } - - /** - * A class used to maintain the virtual time. - */ - private class TimerKeeper { - - private long currentTime = 0; - - /** - * Returns the virtual current time in millis. - * - * @return long representing simulated current time. - */ - long currentTimeInMillis() { - return currentTime; - } - - /** - * Returns the new simulated current time in millis after advancing the absolute value of millis to advance. - * Triggers event execution of all events scheduled for execution at times up to and including the returned - * time. Passing in the number zero has no effect. - * - * @param millisToAdvance the number of millis to advance. - * @return a long representing the current simulated time in millis - */ - long advanceTimeMillis(long millisToAdvance) { - currentTime = (millisToAdvance >= 0) ? (currentTime + millisToAdvance) : (currentTime - millisToAdvance); - if (millisToAdvance != 0) { - executeEventsUpToPresent(); - } - return currentTime; - } - } - - /** - * A queue backed by a linked list. Keeps elements sorted in ascending order of execution time. All calls are safe - * even on empty queue's. - */ - private class TaskQueue { - private final LinkedList<TimerTask> taskList = Lists.newLinkedList(); - - /** - * Adds the task to the queue in ascending order of scheduled execution. If execution time has already passed - * execute immediately. - * - * @param task the task to be added to the queue - */ - void insertOrdered(TimerTask task) { - //Using O(N) insertion because random access is expensive in linked lists worst case is 2N links followed - // for binary insertion vs N for simple insertion. - checkNotNull(task); - if (!staticsPopulated) { - populateStatics(task); - } - long insertTime; - try { - insertTime = TestUtils.getField(task, "nextExecutionTime"); - TestUtils.setField(task, "state", scheduledState); - } catch (TestUtils.TestUtilsException e) { - e.printStackTrace(); - return; - } - //If the task was scheduled in the past or for the current time run it immediately and do not add to the - // queue, subsequent executions will be scheduled as normal - if (insertTime <= timerKeeper.currentTimeInMillis()) { - executeTask(task); - return; - } - - Iterator<TimerTask> iter = taskList.iterator(); - int positionCounter = 0; - long nextTaskTime; - TimerTask currentTask; - while (iter.hasNext()) { - currentTask = iter.next(); - try { - nextTaskTime = TestUtils.getField(currentTask, "nextExecutionTime"); - } catch (TestUtils.TestUtilsException e) { - e.printStackTrace(); - return; - } - if (insertTime < nextTaskTime) { - taskList.add(positionCounter, task); - return; - } - positionCounter++; - } - taskList.addLast(task); - } - - /** - * Returns the first item in the queue (next scheduled for execution) without removing it, returns null if the - * queue is empty. - * - * @return the next TimerTask to run or null if the queue is empty - */ - TimerTask peek() { - if (taskList.isEmpty()) { - return null; - } - return taskList.getFirst(); - } - - /** - * Returns and removes the first item in the queue or null if it is empty. - * - * @return the first element of the queue or null if the queue is empty - */ - TimerTask pop() { - if (taskList.isEmpty()) { - return null; - } - return taskList.pop(); - } - - /** - * Performs a sort on the set of timer tasks, earliest task is first. Does nothing if queue is empty. - */ - void sort() { - if (taskList.isEmpty()) { - return; - } - taskList.sort((o1, o2) -> { - checkNotNull(o1); - checkNotNull(o2); - long executionTimeOne; - long executionTimeTwo; - try { - executionTimeOne = TestUtils.getField(o1, "nextExecutionTime"); - executionTimeTwo = TestUtils.getField(o2, "nextExecutionTime"); - } catch (TestUtils.TestUtilsException e) { - e.printStackTrace(); - throw new RuntimeException("Could not get next execution time."); - } - if (executionTimeOne == executionTimeTwo) { - return 0; - } else if (executionTimeOne < executionTimeTwo) { - return -1; - } else { - return 1; - } - }); - } - - /** - * Returns whether the queue is currently empty. - * - * @return true if the queue is empty, false otherwise - */ - boolean isEmpty() { - return taskList.isEmpty(); - } - - /** - * Clears the underlying list of the queue. - */ - void clear() { - taskList.clear(); - } - - /** - * Removes all cancelled tasks from the queue. Has no effect on behavior. - * - * @return returns the total number of items removed, -1 if list is empty or failure occurs. - */ - int removeCancelled() { - if (taskList.isEmpty()) { - return -1; - } - int removedCount = 0; - Iterator<TimerTask> taskIterator = taskList.iterator(); - TimerTask currTask; - int currState; - while (taskIterator.hasNext()) { - currTask = taskIterator.next(); - try { - currState = TestUtils.getField(currTask, "state"); - } catch (TestUtils.TestUtilsException e) { - logger.error("Could not get task state."); - e.printStackTrace(); - return -1; - } - if (currState == cancelledState) { - removedCount++; - taskIterator.remove(); - } - } - return removedCount; - } - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java deleted file mode 100644 index 36b50e67..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ManuallyAdvancingTimerTest.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import com.google.common.collect.Lists; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Date; -import java.util.TimerTask; -import java.util.concurrent.atomic.AtomicInteger; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.onlab.junit.TestTools.delay; - -/** - * Testing class for manually advancing timer. - */ -public class ManuallyAdvancingTimerTest { - - private ManuallyAdvancingTimer timer; - - /* Generates unique id's for TestTasks */ - private AtomicInteger idGenerator; - - /* Tracks TestTasks in order of creation, tasks are automatically added at creation. */ - private ArrayList<TestTask> taskList; - - /* Total number of tasks run */ - private AtomicInteger tasksRunCount; - - // FIXME if this class fails first try increasing the real time delay to account for heavy system load. - private static final int REAL_TIME_DELAY = 10; - - /** - * Sets up the testing environment. - */ - @Before - public void setup() { - timer = new ManuallyAdvancingTimer(true); - idGenerator = new AtomicInteger(1); - tasksRunCount = new AtomicInteger(0); - taskList = Lists.newArrayList(); - } - - /** - * Tests the one time schedule with delay. - * - * @throws Exception throws an exception if the test fails - */ - @Test - public void testScheduleByDelay() throws Exception { - /* Test scheduling in the future as normal. */ - timer.schedule(new TestTask(), 10); - timer.advanceTimeMillis(5); - assertFalse(taskList.get(0).hasRun()); - timer.advanceTimeMillis(10, REAL_TIME_DELAY); - assertTrue(taskList.get(0).hasRun()); - - /* Test scheduling with negative numbers */ - timer.schedule(new TestTask(), -10); - timer.advanceTimeMillis(5); - assertFalse(taskList.get(1).hasRun()); - timer.advanceTimeMillis(10, REAL_TIME_DELAY); - assertTrue(taskList.get(1).hasRun()); - - /* Reset list, counter and timer for next test */ - taskList.clear(); - idGenerator.set(1); - tasksRunCount.set(0); - - for (int i = 0; i < 50; i++) { - timer.schedule(new TestTask(), i); - } - /* Test that a task scheduled for present is run and not placed in the queue */ - assertEquals("Only the first task should have run.", 1, tasksRunCount.get()); - - for (int i = 2; i <= 50; i++) { - timer.advanceTimeMillis(1, REAL_TIME_DELAY); - assertEquals("One task should be executed per loop", i, tasksRunCount.get()); - } - /* Below tests ordered insertion, this will only be done once, it is the same for all schedule methods. */ - - tasksRunCount.set(0); - - for (int i = 0; i < 10; i++) { - timer.schedule(new TestTask(), 500); - } - - assertEquals("No new tasks should have been run since run count reset.", 0, tasksRunCount.get()); - timer.schedule(new TestTask(), 10); - assertEquals("No new tasks should have been run since run count reset.", 0, tasksRunCount.get()); - timer.advanceTimeMillis(10, REAL_TIME_DELAY); - assertEquals("One new tasks should have been run since run count reset.", 1, tasksRunCount.get()); - timer.advanceTimeMillis(510, REAL_TIME_DELAY); - assertEquals("Eleven new tasks should have been run since run count reset.", 11, tasksRunCount.get()); - } - - /** - * Tests scheduling for a particular date or time which may be in the past. - * - * @throws Exception throws an exception if the test fails - */ - @Test - public void testScheduleByDate() throws Exception { - /* Tests basic scheduling for future times. */ - timer.schedule(new TestTask(), new Date(10)); - timer.advanceTimeMillis(5); - assertFalse(taskList.get(0).hasRun()); - timer.advanceTimeMillis(10, REAL_TIME_DELAY); - assertTrue(taskList.get(0).hasRun()); - - /* Test scheduling with past times numbers */ - timer.schedule(new TestTask(), new Date(0)); - delay(REAL_TIME_DELAY); - assertTrue(taskList.get(1).hasRun()); - - /* Tests cancellation on non-periodic events */ - TestTask task = new TestTask(); - timer.schedule(task, new Date(timer.currentTimeInMillis() + 10)); - task.cancel(); - timer.advanceTimeMillis(12, REAL_TIME_DELAY); - assertFalse(task.hasRun()); - - } - - /** - * Test scheduling beginning after a delay and recurring periodically. - * - * @throws Exception throws an exception if the test fails - */ - @Test - public void testScheduleByDelayPeriodic() throws Exception { - /* Test straightforward periodic execution */ - timer.schedule(new TestTask(), 0, 10); - delay(REAL_TIME_DELAY); - assertEquals("Task should have run once when added.", 1, taskList.get(0).timesRun()); - - /* Tests whether things that are not added to the queue are scheduled for future executions (ones which execute - immediately on add). */ - timer.advanceTimeMillis(10, REAL_TIME_DELAY); - assertEquals("Task should have run once when added.", 2, taskList.get(0).timesRun()); - - /* Tests whether cancellation works on periodic events. */ - taskList.get(0).cancel(); - - timer.advanceTimeMillis(10, REAL_TIME_DELAY); - assertEquals("The task should not have run another time.", 2, taskList.get(0).timesRun()); - - TestTask task = new TestTask(); - timer.schedule(task, 0, 10); - timer.advanceTimeMillis(100, REAL_TIME_DELAY); - assertEquals("Should have run immeditaley and subsequently once during the larger skip", task.timesRun(), 2); - - } - - /** - * Test scheduling beginning at a specified date and recurring periodically. - * - * @throws Exception throws an exception if the test fails - */ - @Test - public void testScheduleByDatePeriodic() throws Exception { - /* Test straightforward periodic execution */ - timer.schedule(new TestTask(), new Date(timer.currentTimeInMillis()), 10); - delay(REAL_TIME_DELAY); - assertEquals("Task should have run once when added.", 1, taskList.get(0).timesRun()); - - /* Tests whether things that are not added to the queue are scheduled for future executions (ones which execute - immediately on add). */ - timer.advanceTimeMillis(10, REAL_TIME_DELAY); - assertEquals("Task should have run once when added.", 2, taskList.get(0).timesRun()); - - /* Tests whether cancellation works on periodic events. */ - taskList.get(0).cancel(); - - timer.advanceTimeMillis(10, REAL_TIME_DELAY); - assertEquals("The task should not have run another time.", 2, taskList.get(0).timesRun()); - - TestTask task = new TestTask(); - timer.schedule(task, new Date(timer.currentTimeInMillis()), 10); - timer.advanceTimeMillis(100, REAL_TIME_DELAY); - assertEquals("Should have run immediately and subsequently once during the larger skip", task.timesRun(), 2); - } - - /* Schedule at fixed rate runs exactly like the two scheduling methods just tested so tests are not included */ - - /** - * Timer task with added functions to make it better for testing. - */ - private class TestTask extends TimerTask { - - /* Remains true once the task has been run at least once */ - private boolean hasRun; - - /* Unique id per event. */ - private int id; - - /* Specifies the number of times an event has run */ - private int timesRun; - - /** - * Constructor initializes id, timesRun, and id fields. - */ - public TestTask() { - id = idGenerator.getAndIncrement(); - timesRun = 0; - hasRun = false; - taskList.add(this); - } - - @Override - public void run() { - this.hasRun = true; - tasksRunCount.incrementAndGet(); - timesRun++; - } - - /** - * Returns whether this event has run. - * - * @return true if the event has run, false otherwise. - */ - public boolean hasRun() { - return hasRun; - } - - /** - * Returns the number of times this task has run. - * - * @return an int representing the number of times this task has been run - */ - public int timesRun() { - return timesRun; - } - - /** - * Returns the unique identifier of this task. - * - * @return a unique integer identifier - */ - public int getId() { - return id; - } - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/PositionalParameterStringFormatterTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/PositionalParameterStringFormatterTest.java deleted file mode 100644 index 9758511f..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/PositionalParameterStringFormatterTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import static org.junit.Assert.*; -import static org.onlab.util.PositionalParameterStringFormatter.format; - -import org.junit.Test; - -public class PositionalParameterStringFormatterTest { - - @Test - public void testFormat0() { - String fmt = "Some string 1 2 3"; - assertEquals("Some string 1 2 3", format(fmt)); - } - - @Test - public void testFormat1() { - String fmt = "Some string {} 2 3"; - assertEquals("Some string 1 2 3", format(fmt, 1)); - } - - @Test - public void testFormat2() { - String fmt = "Some string {} 2 {}"; - assertEquals("Some string 1 2 3", format(fmt, 1, "3")); - } - - @Test - public void testFormatNull() { - String fmt = "Some string {} 2 {}"; - assertEquals("Some string 1 2 null", format(fmt, 1, null)); - } - - @Test - public void testFormatExtraBracket() { - String fmt = "Some string {} 2 {}"; - assertEquals("Some string 1 2 {}", format(fmt, 1)); - } - - @Test - public void testFormatMissingBracket() { - String fmt = "Some string 1 2 3"; - assertEquals("Some string 1 2 3", format(fmt, 7)); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/RetryingFunctionTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/RetryingFunctionTest.java deleted file mode 100644 index 4b08d2fc..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/RetryingFunctionTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Unit tests for RetryingFunction. - * - */ -public class RetryingFunctionTest { - - private int round; - - @Before - public void setUp() { - round = 1; - } - - @After - public void tearDown() { - round = 0; - } - - @Test(expected = RetryableException.class) - public void testNoRetries() { - new RetryingFunction<>(this::succeedAfterOneFailure, RetryableException.class, 0, 10).apply(null); - } - - @Test - public void testSuccessAfterOneRetry() { - new RetryingFunction<>(this::succeedAfterOneFailure, RetryableException.class, 1, 10).apply(null); - } - - @Test(expected = RetryableException.class) - public void testFailureAfterOneRetry() { - new RetryingFunction<>(this::succeedAfterTwoFailures, RetryableException.class, 1, 10).apply(null); - } - - @Test - public void testFailureAfterTwoRetries() { - new RetryingFunction<>(this::succeedAfterTwoFailures, RetryableException.class, 2, 10).apply(null); - } - - @Test(expected = NonRetryableException.class) - public void testFailureWithNonRetryableFailure() { - new RetryingFunction<>(this::failCompletely, RetryableException.class, 2, 10).apply(null); - } - - private String succeedAfterOneFailure(String input) { - if (round++ <= 1) { - throw new RetryableException(); - } else { - return "pass"; - } - } - - private String succeedAfterTwoFailures(String input) { - if (round++ <= 2) { - throw new RetryableException(); - } else { - return "pass"; - } - } - - private String failCompletely(String input) { - if (round++ <= 1) { - throw new NonRetryableException(); - } else { - return "pass"; - } - } - - private class RetryableException extends RuntimeException { - } - - private class NonRetryableException extends RuntimeException { - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SharedExecutorsTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SharedExecutorsTest.java deleted file mode 100644 index 1730ca1f..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SharedExecutorsTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.Test; - -import java.util.concurrent.ExecutorService; - -import static org.junit.Assert.*; - -/** - * Tests of the SharedExecutors Test. - */ -public class SharedExecutorsTest { - - @Test - public void singleThread() { - ExecutorService a = SharedExecutors.getSingleThreadExecutor(); - assertNotNull("ExecutorService must not be null", a); - ExecutorService b = SharedExecutors.getSingleThreadExecutor(); - assertSame("factories should be same", a, b); - - } - - @Test - public void poolThread() { - ExecutorService a = SharedExecutors.getPoolThreadExecutor(); - assertNotNull("ExecutorService must not be null", a); - ExecutorService b = SharedExecutors.getPoolThreadExecutor(); - assertSame("factories should be same", a, b); - - } - - @Test - public void timer() { - java.util.Timer a = SharedExecutors.getTimer(); - assertNotNull("Timer must not be null", a); - java.util.Timer b = SharedExecutors.getTimer(); - assertSame("factories should be same", a, b); - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SlidingWindowCounterTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SlidingWindowCounterTest.java deleted file mode 100644 index c15cc8a6..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SlidingWindowCounterTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import static junit.framework.TestCase.fail; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Unit tests for the sliding window counter. - */ - -@Ignore("Disable these for now because of intermittent load related failures on Jenkins runs.") -public class SlidingWindowCounterTest { - - private SlidingWindowCounter counter; - - @Before - public void setUp() { - counter = new SlidingWindowCounter(2); - } - - @After - public void tearDown() { - counter.destroy(); - } - - @Test - public void testIncrementCount() { - assertEquals(0, counter.get(1)); - assertEquals(0, counter.get(2)); - counter.incrementCount(); - assertEquals(1, counter.get(1)); - assertEquals(1, counter.get(2)); - counter.incrementCount(2); - assertEquals(3, counter.get(2)); - } - - @Test - public void testSlide() { - counter.incrementCount(); - counter.advanceHead(); - assertEquals(0, counter.get(1)); - assertEquals(1, counter.get(2)); - counter.incrementCount(2); - assertEquals(2, counter.get(1)); - assertEquals(3, counter.get(2)); - } - - @Test - public void testWrap() { - counter.incrementCount(); - counter.advanceHead(); - counter.incrementCount(2); - counter.advanceHead(); - assertEquals(0, counter.get(1)); - assertEquals(2, counter.get(2)); - counter.advanceHead(); - assertEquals(0, counter.get(1)); - assertEquals(0, counter.get(2)); - - } - - @Test - public void testCornerCases() { - try { - counter.get(3); - fail("Exception should have been thrown"); - } catch (IllegalArgumentException e) { - assertTrue(true); - } - - try { - new SlidingWindowCounter(0); - fail("Exception should have been thrown"); - } catch (IllegalArgumentException e) { - assertTrue(true); - } - - try { - new SlidingWindowCounter(-1); - fail("Exception should have been thrown"); - } catch (IllegalArgumentException e) { - assertTrue(true); - } - } -} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ToolsTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ToolsTest.java deleted file mode 100644 index 56f0f957..00000000 --- a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ToolsTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.util; - -import org.junit.Test; -import org.onlab.junit.TestTools; - -import java.util.concurrent.ThreadFactory; - -import static org.junit.Assert.*; -import static org.onlab.junit.TestTools.assertAfter; - -/** - * Test of the miscellaneous tools. - */ -public class ToolsTest { - - @Test - public void fromHex() throws Exception { - assertEquals(15, Tools.fromHex("0f")); - assertEquals(16, Tools.fromHex("10")); - assertEquals(65535, Tools.fromHex("ffff")); - assertEquals(4096, Tools.fromHex("1000")); - assertEquals(0xffffffffffffffffL, Tools.fromHex("ffffffffffffffff")); - } - - @Test - public void toHex() throws Exception { - assertEquals("0f", Tools.toHex(15, 2)); - assertEquals("ffff", Tools.toHex(65535, 4)); - assertEquals("1000", Tools.toHex(4096, 4)); - assertEquals("000000000000000f", Tools.toHex(15)); - assertEquals("ffffffffffffffff", Tools.toHex(0xffffffffffffffffL)); - - } - - @Test - public void namedThreads() { - ThreadFactory f = Tools.namedThreads("foo-%d"); - Thread t = f.newThread(() -> TestTools.print("yo")); - assertTrue("wrong pattern", t.getName().startsWith("foo-")); - } - - @Test - public void groupedThreads() { - ThreadFactory f = Tools.groupedThreads("foo/bar-me", "foo-%d"); - Thread t = f.newThread(() -> TestTools.print("yo")); - assertTrue("wrong pattern", t.getName().startsWith("foo-bar-me-foo-")); - assertTrue("wrong group", t.getThreadGroup().getName().equals("foo/bar-me")); - } - - @Test - public void exceptionHandler() throws InterruptedException { - ThreadFactory f = Tools.namedThreads("foo"); - Thread t = f.newThread(() -> { - throw new IllegalStateException("BOOM!"); - }); - assertNotNull("thread should have exception handler", t.getUncaughtExceptionHandler()); - t.start(); - assertAfter(100, () -> assertEquals("incorrect thread state", Thread.State.TERMINATED, t.getState())); - } - -} diff --git a/framework/src/onos/utils/netty/pom.xml b/framework/src/onos/utils/netty/pom.xml deleted file mode 100644 index 7bae10aa..00000000 --- a/framework/src/onos/utils/netty/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-netty</artifactId> - <packaging>bundle</packaging> - - <description>Network I/O using Netty framework</description> - - <dependencies> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava-testlib</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onos-api</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-misc</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>commons-pool</groupId> - <artifactId>commons-pool</artifactId> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-common</artifactId> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-buffer</artifactId> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-transport</artifactId> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-handler</artifactId> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-codec</artifactId> - </dependency> - <dependency> - <groupId>io.netty</groupId> - <artifactId>netty-transport-native-epoll</artifactId> - <version>${netty4.version}</version> - </dependency> - </dependencies> -</project> diff --git a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/DecoderState.java b/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/DecoderState.java deleted file mode 100644 index c4393018..00000000 --- a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/DecoderState.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.netty; - -/** - * State transitions a decoder goes through as it is decoding an incoming message. - */ -public enum DecoderState { - READ_MESSAGE_PREAMBLE, - READ_MESSAGE_ID, - READ_SENDER_IP_VERSION, - READ_SENDER_IP, - READ_SENDER_PORT, - READ_MESSAGE_TYPE_LENGTH, - READ_MESSAGE_TYPE, - READ_CONTENT_LENGTH, - READ_CONTENT -} diff --git a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/InternalMessage.java b/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/InternalMessage.java deleted file mode 100644 index 102e2a22..00000000 --- a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/InternalMessage.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.netty; - -import org.onlab.util.ByteArraySizeHashPrinter; -import org.onosproject.store.cluster.messaging.Endpoint; - -import com.google.common.base.MoreObjects; - -/** - * Internal message representation with additional attributes - * for supporting, synchronous request/reply behavior. - */ -public final class InternalMessage { - - private final long id; - private final Endpoint sender; - private final String type; - private final byte[] payload; - - public InternalMessage(long id, Endpoint sender, String type, byte[] payload) { - this.id = id; - this.sender = sender; - this.type = type; - this.payload = payload; - } - - public long id() { - return id; - } - - public String type() { - return type; - } - - public Endpoint sender() { - return sender; - } - - public byte[] payload() { - return payload; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("id", id) - .add("type", type) - .add("sender", sender) - .add("payload", ByteArraySizeHashPrinter.of(payload)) - .toString(); - } -} diff --git a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/MessageDecoder.java b/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/MessageDecoder.java deleted file mode 100644 index af52a41c..00000000 --- a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/MessageDecoder.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.netty; - -import static com.google.common.base.Preconditions.checkState; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ReplayingDecoder; - -import java.util.List; - -import org.onlab.packet.IpAddress; -import org.onlab.packet.IpAddress.Version; -import org.onosproject.store.cluster.messaging.Endpoint; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Charsets; - -/** - * Decoder for inbound messages. - */ -public class MessageDecoder extends ReplayingDecoder<DecoderState> { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private final int correctPreamble; - private long messageId; - private int preamble; - private Version ipVersion; - private IpAddress senderIp; - private int senderPort; - private int messageTypeLength; - private String messageType; - private int contentLength; - - public MessageDecoder(int correctPreamble) { - super(DecoderState.READ_MESSAGE_PREAMBLE); - this.correctPreamble = correctPreamble; - } - - @Override - protected void decode( - ChannelHandlerContext context, - ByteBuf buffer, - List<Object> out) throws Exception { - - switch (state()) { - case READ_MESSAGE_PREAMBLE: - preamble = buffer.readInt(); - if (preamble != correctPreamble) { - throw new IllegalStateException("This message had an incorrect preamble."); - } - checkpoint(DecoderState.READ_MESSAGE_ID); - case READ_MESSAGE_ID: - messageId = buffer.readLong(); - checkpoint(DecoderState.READ_SENDER_IP_VERSION); - case READ_SENDER_IP_VERSION: - ipVersion = buffer.readByte() == 0x0 ? Version.INET : Version.INET6; - checkpoint(DecoderState.READ_SENDER_IP); - case READ_SENDER_IP: - byte[] octets = new byte[IpAddress.byteLength(ipVersion)]; - buffer.readBytes(octets); - senderIp = IpAddress.valueOf(ipVersion, octets); - checkpoint(DecoderState.READ_SENDER_PORT); - case READ_SENDER_PORT: - senderPort = buffer.readInt(); - checkpoint(DecoderState.READ_MESSAGE_TYPE_LENGTH); - case READ_MESSAGE_TYPE_LENGTH: - messageTypeLength = buffer.readInt(); - checkpoint(DecoderState.READ_MESSAGE_TYPE); - case READ_MESSAGE_TYPE: - byte[] messageTypeBytes = new byte[messageTypeLength]; - buffer.readBytes(messageTypeBytes); - messageType = new String(messageTypeBytes, Charsets.UTF_8); - checkpoint(DecoderState.READ_CONTENT_LENGTH); - case READ_CONTENT_LENGTH: - contentLength = buffer.readInt(); - checkpoint(DecoderState.READ_CONTENT); - case READ_CONTENT: - //TODO Perform a sanity check on the size before allocating - byte[] payload = new byte[contentLength]; - buffer.readBytes(payload); - InternalMessage message = new InternalMessage(messageId, - new Endpoint(senderIp, senderPort), - messageType, - payload); - out.add(message); - checkpoint(DecoderState.READ_MESSAGE_PREAMBLE); - break; - default: - checkState(false, "Must not be here"); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { - log.error("Exception inside channel handling pipeline.", cause); - context.close(); - } -} diff --git a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/MessageEncoder.java b/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/MessageEncoder.java deleted file mode 100644 index c74c1de9..00000000 --- a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/MessageEncoder.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.netty; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; - -import java.io.IOException; - -import org.onlab.packet.IpAddress; -import org.onlab.packet.IpAddress.Version; -import org.onosproject.store.cluster.messaging.Endpoint; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Charsets; - -/** - * Encode InternalMessage out into a byte buffer. - */ -@Sharable -public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { - - private final int preamble; - - public MessageEncoder(int preamble) { - super(); - this.preamble = preamble; - } - - private final Logger log = LoggerFactory.getLogger(getClass()); - - @Override - protected void encode( - ChannelHandlerContext context, - InternalMessage message, - ByteBuf out) throws Exception { - - out.writeInt(this.preamble); - - // write message id - out.writeLong(message.id()); - - Endpoint sender = message.sender(); - - IpAddress senderIp = sender.host(); - if (senderIp.version() == Version.INET) { - out.writeByte(0); - } else { - out.writeByte(1); - } - out.writeBytes(senderIp.toOctets()); - - // write sender port - out.writeInt(sender.port()); - - byte[] messageTypeBytes = message.type().getBytes(Charsets.UTF_8); - - // write length of message type - out.writeInt(messageTypeBytes.length); - - // write message type bytes - out.writeBytes(messageTypeBytes); - - byte[] payload = message.payload(); - - // write payload length - out.writeInt(payload.length); - - // write payload. - out.writeBytes(payload); - } - - @Override - public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { - if (cause instanceof IOException) { - log.debug("IOException inside channel handling pipeline.", cause); - } else { - log.error("non-IOException inside channel handling pipeline.", cause); - } - context.close(); - } -} diff --git a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/NettyMessaging.java b/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/NettyMessaging.java deleted file mode 100644 index 2dda747d..00000000 --- a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/NettyMessaging.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.netty; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalListener; -import com.google.common.cache.RemovalNotification; -import io.netty.bootstrap.Bootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.epoll.EpollServerSocketChannel; -import io.netty.channel.epoll.EpollSocketChannel; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; -import org.apache.commons.pool.KeyedPoolableObjectFactory; -import org.apache.commons.pool.impl.GenericKeyedObjectPool; -import org.onosproject.store.cluster.messaging.Endpoint; -import org.onosproject.store.cluster.messaging.MessagingService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.TrustManagerFactory; -import java.io.FileInputStream; -import java.io.IOException; -import java.security.KeyStore; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * Implementation of MessagingService based on <a href="http://netty.io/">Netty</a> framework. - */ -public class NettyMessaging implements MessagingService { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private static final String REPLY_MESSAGE_TYPE = "NETTY_MESSAGING_REQUEST_REPLY"; - - private Endpoint localEp; - private int preamble; - private final AtomicBoolean started = new AtomicBoolean(false); - private final Map<String, Consumer<InternalMessage>> handlers = new ConcurrentHashMap<>(); - private final AtomicLong messageIdGenerator = new AtomicLong(0); - private final Cache<Long, CompletableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder() - .expireAfterWrite(10, TimeUnit.SECONDS) - .removalListener(new RemovalListener<Long, CompletableFuture<byte[]>>() { - @Override - public void onRemoval(RemovalNotification<Long, CompletableFuture<byte[]>> entry) { - if (entry.wasEvicted()) { - entry.getValue().completeExceptionally(new TimeoutException("Timedout waiting for reply")); - } - } - }) - .build(); - - private final GenericKeyedObjectPool<Endpoint, Channel> channels - = new GenericKeyedObjectPool<Endpoint, Channel>(new OnosCommunicationChannelFactory()); - - private EventLoopGroup serverGroup; - private EventLoopGroup clientGroup; - private Class<? extends ServerChannel> serverChannelClass; - private Class<? extends Channel> clientChannelClass; - - protected static final boolean TLS_DISABLED = false; - protected boolean enableNettyTls = TLS_DISABLED; - - protected String ksLocation; - protected String tsLocation; - protected char[] ksPwd; - protected char[] tsPwd; - - private void initEventLoopGroup() { - // try Epoll first and if that does work, use nio. - try { - clientGroup = new EpollEventLoopGroup(); - serverGroup = new EpollEventLoopGroup(); - serverChannelClass = EpollServerSocketChannel.class; - clientChannelClass = EpollSocketChannel.class; - return; - } catch (Throwable e) { - log.debug("Failed to initialize native (epoll) transport. " - + "Reason: {}. Proceeding with nio.", e.getMessage()); - } - clientGroup = new NioEventLoopGroup(); - serverGroup = new NioEventLoopGroup(); - serverChannelClass = NioServerSocketChannel.class; - clientChannelClass = NioSocketChannel.class; - } - - public void start(int preamble, Endpoint localEp) throws Exception { - if (started.get()) { - log.warn("Already running at local endpoint: {}", localEp); - return; - } - this.preamble = preamble; - this.localEp = localEp; - channels.setLifo(true); - channels.setTestOnBorrow(true); - channels.setTestOnReturn(true); - channels.setMinEvictableIdleTimeMillis(60_000L); - channels.setTimeBetweenEvictionRunsMillis(30_000L); - initEventLoopGroup(); - startAcceptingConnections(); - started.set(true); - } - - public void stop() throws Exception { - if (started.get()) { - channels.close(); - serverGroup.shutdownGracefully(); - clientGroup.shutdownGracefully(); - started.set(false); - } - } - - @Override - public CompletableFuture<Void> sendAsync(Endpoint ep, String type, byte[] payload) { - InternalMessage message = new InternalMessage(messageIdGenerator.incrementAndGet(), - localEp, - type, - payload); - return sendAsync(ep, message); - } - - protected CompletableFuture<Void> sendAsync(Endpoint ep, InternalMessage message) { - CompletableFuture<Void> future = new CompletableFuture<>(); - try { - if (ep.equals(localEp)) { - dispatchLocally(message); - future.complete(null); - } else { - Channel channel = null; - try { - channel = channels.borrowObject(ep); - channel.writeAndFlush(message).addListener(channelFuture -> { - if (!channelFuture.isSuccess()) { - future.completeExceptionally(channelFuture.cause()); - } else { - future.complete(null); - } - }); - } finally { - channels.returnObject(ep, channel); - } - } - } catch (Exception e) { - future.completeExceptionally(e); - } - return future; - } - - @Override - public CompletableFuture<byte[]> sendAndReceive(Endpoint ep, String type, byte[] payload) { - CompletableFuture<byte[]> response = new CompletableFuture<>(); - Long messageId = messageIdGenerator.incrementAndGet(); - responseFutures.put(messageId, response); - InternalMessage message = new InternalMessage(messageId, localEp, type, payload); - try { - sendAsync(ep, message); - } catch (Exception e) { - responseFutures.invalidate(messageId); - response.completeExceptionally(e); - } - return response; - } - - @Override - public void registerHandler(String type, Consumer<byte[]> handler, Executor executor) { - handlers.put(type, message -> executor.execute(() -> handler.accept(message.payload()))); - } - - @Override - public void registerHandler(String type, Function<byte[], byte[]> handler, Executor executor) { - handlers.put(type, message -> executor.execute(() -> { - byte[] responsePayload = handler.apply(message.payload()); - if (responsePayload != null) { - InternalMessage response = new InternalMessage(message.id(), - localEp, - REPLY_MESSAGE_TYPE, - responsePayload); - sendAsync(message.sender(), response).whenComplete((result, error) -> { - if (error != null) { - log.debug("Failed to respond", error); - } - }); - } - })); - } - - @Override - public void registerHandler(String type, Function<byte[], CompletableFuture<byte[]>> handler) { - handlers.put(type, message -> { - handler.apply(message.payload()).whenComplete((result, error) -> { - if (error == null) { - InternalMessage response = new InternalMessage(message.id(), - localEp, - REPLY_MESSAGE_TYPE, - result); - sendAsync(message.sender(), response).whenComplete((r, e) -> { - if (e != null) { - log.debug("Failed to respond", e); - } - }); - } - }); - }); - } - - @Override - public void unregisterHandler(String type) { - handlers.remove(type); - } - - private void startAcceptingConnections() throws InterruptedException { - ServerBootstrap b = new ServerBootstrap(); - b.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024); - b.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024); - b.option(ChannelOption.SO_RCVBUF, 1048576); - b.option(ChannelOption.TCP_NODELAY, true); - b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); - b.group(serverGroup, clientGroup); - b.channel(serverChannelClass); - if (enableNettyTls) { - b.childHandler(new SslServerCommunicationChannelInitializer()); - } else { - b.childHandler(new OnosCommunicationChannelInitializer()); - } - b.option(ChannelOption.SO_BACKLOG, 128); - b.childOption(ChannelOption.SO_KEEPALIVE, true); - - // Bind and start to accept incoming connections. - b.bind(localEp.port()).sync().addListener(future -> { - if (future.isSuccess()) { - log.info("{} accepting incoming connections on port {}", localEp.host(), localEp.port()); - } else { - log.warn("{} failed to bind to port {}", localEp.host(), localEp.port(), future.cause()); - } - }); - } - - private class OnosCommunicationChannelFactory - implements KeyedPoolableObjectFactory<Endpoint, Channel> { - - @Override - public void activateObject(Endpoint endpoint, Channel channel) - throws Exception { - } - - @Override - public void destroyObject(Endpoint ep, Channel channel) throws Exception { - log.debug("Closing connection to {}", ep); - channel.close(); - } - - @Override - public Channel makeObject(Endpoint ep) throws Exception { - Bootstrap bootstrap = new Bootstrap(); - bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); - bootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 10 * 64 * 1024); - bootstrap.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 10 * 32 * 1024); - bootstrap.option(ChannelOption.SO_SNDBUF, 1048576); - bootstrap.group(clientGroup); - // TODO: Make this faster: - // http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0 - bootstrap.channel(clientChannelClass); - bootstrap.option(ChannelOption.SO_KEEPALIVE, true); - if (enableNettyTls) { - bootstrap.handler(new SslClientCommunicationChannelInitializer()); - } else { - bootstrap.handler(new OnosCommunicationChannelInitializer()); - } - // Start the client. - ChannelFuture f = bootstrap.connect(ep.host().toString(), ep.port()).sync(); - log.debug("Established a new connection to {}", ep); - return f.channel(); - } - - @Override - public void passivateObject(Endpoint ep, Channel channel) - throws Exception { - } - - @Override - public boolean validateObject(Endpoint ep, Channel channel) { - return channel.isOpen(); - } - } - - private class SslServerCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { - - private final ChannelHandler dispatcher = new InboundMessageDispatcher(); - private final ChannelHandler encoder = new MessageEncoder(preamble); - - @Override - protected void initChannel(SocketChannel channel) throws Exception { - TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - KeyStore ts = KeyStore.getInstance("JKS"); - ts.load(new FileInputStream(tsLocation), tsPwd); - tmFactory.init(ts); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(new FileInputStream(ksLocation), ksPwd); - kmf.init(ks, ksPwd); - - SSLContext serverContext = SSLContext.getInstance("TLS"); - serverContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null); - - SSLEngine serverSslEngine = serverContext.createSSLEngine(); - - serverSslEngine.setNeedClientAuth(true); - serverSslEngine.setUseClientMode(false); - serverSslEngine.setEnabledProtocols(serverSslEngine.getSupportedProtocols()); - serverSslEngine.setEnabledCipherSuites(serverSslEngine.getSupportedCipherSuites()); - serverSslEngine.setEnableSessionCreation(true); - - channel.pipeline().addLast("ssl", new io.netty.handler.ssl.SslHandler(serverSslEngine)) - .addLast("encoder", encoder) - .addLast("decoder", new MessageDecoder(preamble)) - .addLast("handler", dispatcher); - } - - } - - private class SslClientCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { - - private final ChannelHandler dispatcher = new InboundMessageDispatcher(); - private final ChannelHandler encoder = new MessageEncoder(preamble); - - @Override - protected void initChannel(SocketChannel channel) throws Exception { - TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - KeyStore ts = KeyStore.getInstance("JKS"); - ts.load(new FileInputStream(tsLocation), tsPwd); - tmFactory.init(ts); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(new FileInputStream(ksLocation), ksPwd); - kmf.init(ks, ksPwd); - - SSLContext clientContext = SSLContext.getInstance("TLS"); - clientContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null); - - SSLEngine clientSslEngine = clientContext.createSSLEngine(); - - clientSslEngine.setUseClientMode(true); - clientSslEngine.setEnabledProtocols(clientSslEngine.getSupportedProtocols()); - clientSslEngine.setEnabledCipherSuites(clientSslEngine.getSupportedCipherSuites()); - clientSslEngine.setEnableSessionCreation(true); - - channel.pipeline().addLast("ssl", new io.netty.handler.ssl.SslHandler(clientSslEngine)) - .addLast("encoder", encoder) - .addLast("decoder", new MessageDecoder(preamble)) - .addLast("handler", dispatcher); - } - - } - - private class OnosCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { - - private final ChannelHandler dispatcher = new InboundMessageDispatcher(); - private final ChannelHandler encoder = new MessageEncoder(preamble); - - @Override - protected void initChannel(SocketChannel channel) throws Exception { - channel.pipeline() - .addLast("encoder", encoder) - .addLast("decoder", new MessageDecoder(preamble)) - .addLast("handler", dispatcher); - } - } - - @ChannelHandler.Sharable - private class InboundMessageDispatcher extends SimpleChannelInboundHandler<InternalMessage> { - - @Override - protected void channelRead0(ChannelHandlerContext ctx, InternalMessage message) throws Exception { - try { - dispatchLocally(message); - } catch (RejectedExecutionException e) { - log.warn("Unable to dispatch message due to {}", e.getMessage()); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { - log.error("Exception inside channel handling pipeline.", cause); - context.close(); - } - } - private void dispatchLocally(InternalMessage message) throws IOException { - String type = message.type(); - if (REPLY_MESSAGE_TYPE.equals(type)) { - try { - CompletableFuture<byte[]> futureResponse = - responseFutures.getIfPresent(message.id()); - if (futureResponse != null) { - futureResponse.complete(message.payload()); - } else { - log.warn("Received a reply for message id:[{}]. " - + " from {}. But was unable to locate the" - + " request handle", message.id(), message.sender()); - } - } finally { - responseFutures.invalidate(message.id()); - } - return; - } - Consumer<InternalMessage> handler = handlers.get(type); - if (handler != null) { - handler.accept(message); - } else { - log.debug("No handler registered for {}", type); - } - } -} diff --git a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/package-info.java b/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/package-info.java deleted file mode 100644 index 2d6257ff..00000000 --- a/framework/src/onos/utils/netty/src/main/java/org/onlab/netty/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Asynchronous messaging APIs implemented using the Netty framework. - */ -package org.onlab.netty; diff --git a/framework/src/onos/utils/nio/pom.xml b/framework/src/onos/utils/nio/pom.xml deleted file mode 100644 index b92c9b7b..00000000 --- a/framework/src/onos/utils/nio/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-nio</artifactId> - <packaging>bundle</packaging> - - <description>Fast network I/O using Java NIO</description> - - <dependencies> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava-testlib</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>commons-pool</groupId> - <artifactId>commons-pool</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onos-api</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-misc</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-junit</artifactId> - <scope>test</scope> - </dependency> - </dependencies> -</project> diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AbstractMessage.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AbstractMessage.java deleted file mode 100644 index 16bb9359..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AbstractMessage.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -/** - * Base {@link Message} implementation. - */ -public abstract class AbstractMessage implements Message { - - protected int length; - - @Override - public int length() { - return length; - } - -} diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AcceptorLoop.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AcceptorLoop.java deleted file mode 100644 index e416f3be..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/AcceptorLoop.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import java.io.IOException; -import java.net.SocketAddress; -import java.net.StandardSocketOptions; -import java.nio.channels.SelectionKey; -import java.nio.channels.ServerSocketChannel; -import java.util.Iterator; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Selector loop derivative tailored to acceptConnection inbound connections. - */ -public abstract class AcceptorLoop extends SelectorLoop { - - private SocketAddress listenAddress; - private ServerSocketChannel socketChannel; - - /** - * Creates an acceptor loop with the specified selection timeout and - * accepting connections on the the given address. - * - * @param selectTimeout selection timeout; specified in millis - * @param listenAddress socket address where to listen for connections - * @throws IOException if the backing selector cannot be opened - */ - public AcceptorLoop(long selectTimeout, SocketAddress listenAddress) - throws IOException { - super(selectTimeout); - this.listenAddress = checkNotNull(listenAddress, "Address cannot be null"); - } - - /** - * Hook to accept an inbound connection on the specified socket channel. - * - * @param channel socketChannel where an accept operation awaits - * @throws IOException if the accept operation cannot be processed - */ - protected abstract void acceptConnection(ServerSocketChannel channel) throws IOException; - - /** - * Opens a new server socket channel configured in non-blocking mode and - * bound to the loop's listen address. - * - * @throws IOException if unable to open or configure the socket channel - */ - protected synchronized void openChannel() throws IOException { - socketChannel = ServerSocketChannel.open(); - socketChannel.configureBlocking(false); - socketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); - socketChannel.register(selector, SelectionKey.OP_ACCEPT); - socketChannel.bind(listenAddress); - } - - /** - * Closes the server socket channel. - * - * @throws IOException if unable to close the socketChannel - */ - protected synchronized void closechannel() throws IOException { - if (socketChannel != null) { - socketChannel.close(); - socketChannel = null; - } - } - - @Override - public void shutdown() { - try { - closechannel(); - } catch (IOException e) { - log.warn("Unable to close the socketChannel", e); - } - super.shutdown(); - } - - @Override - protected void loop() throws IOException { - openChannel(); - notifyReady(); - - // Keep looping until told otherwise. - while (isRunning()) { - // Attempt a selection; if no operations selected or if signalled - // to shutdown, spin through. - int count = selector.select(selectTimeout); - if (count == 0 || !isRunning()) { - continue; - } - - // Iterate over all keys selected for an operation and process them. - Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); - while (keys.hasNext()) { - // Fetch the key and remove it from the pending list. - SelectionKey key = keys.next(); - keys.remove(); - - // If the key has a pending acceptConnection operation, process it. - if (key.isAcceptable()) { - acceptConnection((ServerSocketChannel) key.channel()); - } - } - } - } - -} - diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/IOLoop.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/IOLoop.java deleted file mode 100644 index 106df7b2..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/IOLoop.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import java.io.IOException; -import java.nio.channels.ByteChannel; -import java.nio.channels.CancelledKeyException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.SocketChannel; -import java.util.Iterator; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * I/O loop for driving inbound & outbound {@link Message} transfer via - * {@link MessageStream}. - * - * @param <M> message type - * @param <S> message stream type - */ -public abstract class IOLoop<M extends Message, S extends MessageStream<M>> - extends SelectorLoop { - - // Queue of requests for new message streams to enter the IO loop processing. - private final Queue<NewStreamRequest> newStreamRequests = new ConcurrentLinkedQueue<>(); - - // Carries information required for admitting a new message stream. - private class NewStreamRequest { - private final S stream; - private final SelectableChannel channel; - private final int op; - - public NewStreamRequest(S stream, SelectableChannel channel, int op) { - this.stream = stream; - this.channel = channel; - this.op = op; - } - } - - // Set of message streams currently admitted into the IO loop. - private final Set<MessageStream<M>> streams = new CopyOnWriteArraySet<>(); - - /** - * Creates an IO loop with the given selection timeout. - * - * @param timeout selection timeout in milliseconds - * @throws IOException if the backing selector cannot be opened - */ - public IOLoop(long timeout) throws IOException { - super(timeout); - } - - /** - * Returns the number of message stream in custody of the loop. - * - * @return number of message streams - */ - public int streamCount() { - return streams.size(); - } - - /** - * Creates a new message stream backed by the specified socket channel. - * - * @param byteChannel backing byte channel - * @return newly created message stream - */ - protected abstract S createStream(ByteChannel byteChannel); - - /** - * Removes the specified message stream from the IO loop. - * - * @param stream message stream to remove - */ - protected void removeStream(MessageStream<M> stream) { - streams.remove(stream); - } - - /** - * Processes the list of messages extracted from the specified message - * stream. - * - * @param messages non-empty list of received messages - * @param stream message stream from which the messages were extracted - */ - protected abstract void processMessages(List<M> messages, MessageStream<M> stream); - - /** - * Completes connection request pending on the given selection key. - * - * @param key selection key holding the pending connect operation. - * @throws IOException when I/O exception of some sort has occurred - */ - protected void connect(SelectionKey key) throws IOException { - SocketChannel ch = (SocketChannel) key.channel(); - ch.finishConnect(); - if (key.isValid()) { - key.interestOps(SelectionKey.OP_READ); - } - } - - /** - * Processes an IO operation pending on the specified key. - * - * @param key selection key holding the pending I/O operation. - */ - protected void processKeyOperation(SelectionKey key) { - @SuppressWarnings("unchecked") - S stream = (S) key.attachment(); - - try { - // If the key is not valid, bail out. - if (!key.isValid()) { - stream.close(); - return; - } - - // If there is a pending connect operation, complete it. - if (key.isConnectable()) { - try { - connect(key); - } catch (IOException | IllegalStateException e) { - log.warn("Unable to complete connection", e); - } - } - - // If there is a read operation, slurp as much data as possible. - if (key.isReadable()) { - List<M> messages = stream.read(); - - // No messages or failed flush imply disconnect; bail. - if (messages == null || stream.hadError()) { - stream.close(); - return; - } - - // If there were any messages read, process them. - if (!messages.isEmpty()) { - try { - processMessages(messages, stream); - } catch (RuntimeException e) { - onError(stream, e); - } - } - } - - // If there are pending writes, flush them - if (key.isWritable()) { - stream.flushIfPossible(); - } - - // If there were any issued flushing, close the stream. - if (stream.hadError()) { - stream.close(); - } - - } catch (CancelledKeyException e) { - // Key was cancelled, so silently close the stream - stream.close(); - } catch (IOException e) { - if (!stream.isClosed() && !isResetByPeer(e)) { - log.warn("Unable to process IO", e); - } - stream.close(); - } - } - - // Indicates whether or not this exception is caused by 'reset by peer'. - private boolean isResetByPeer(IOException e) { - Throwable cause = e.getCause(); - return cause != null && cause instanceof IOException && - cause.getMessage().contains("reset by peer"); - } - - /** - * Hook to allow intercept of any errors caused during message processing. - * Default behaviour is to rethrow the error. - * - * @param stream message stream involved in the error - * @param error the runtime exception - */ - protected void onError(S stream, RuntimeException error) { - throw error; - } - - /** - * Admits a new message stream backed by the specified socket channel - * with a pending accept operation. - * - * @param channel backing socket channel - * @return newly accepted message stream - */ - public S acceptStream(SocketChannel channel) { - return createAndAdmit(channel, SelectionKey.OP_READ); - } - - - /** - * Admits a new message stream backed by the specified socket channel - * with a pending connect operation. - * - * @param channel backing socket channel - * @return newly connected message stream - */ - public S connectStream(SocketChannel channel) { - return createAndAdmit(channel, SelectionKey.OP_CONNECT); - } - - /** - * Creates a new message stream backed by the specified socket channel - * and admits it into the IO loop. - * - * @param channel socket channel - * @param op pending operations mask to be applied to the selection - * key as a set of initial interestedOps - * @return newly created message stream - */ - private synchronized S createAndAdmit(SocketChannel channel, int op) { - S stream = createStream(channel); - streams.add(stream); - newStreamRequests.add(new NewStreamRequest(stream, channel, op)); - selector.wakeup(); - return stream; - } - - /** - * Safely admits new streams into the IO loop. - */ - private void admitNewStreams() { - Iterator<NewStreamRequest> it = newStreamRequests.iterator(); - while (isRunning() && it.hasNext()) { - try { - NewStreamRequest request = it.next(); - it.remove(); - SelectionKey key = request.channel.register(selector, request.op, - request.stream); - request.stream.setKey(key); - } catch (ClosedChannelException e) { - log.warn("Unable to admit new message stream", e); - } - } - } - - @Override - protected void loop() throws IOException { - notifyReady(); - - // Keep going until told otherwise. - while (isRunning()) { - admitNewStreams(); - - // Process flushes & write selects on all streams - for (MessageStream<M> stream : streams) { - stream.flushIfWriteNotPending(); - } - - // Select keys and process them. - int count = selector.select(selectTimeout); - if (count > 0 && isRunning()) { - Iterator<SelectionKey> it = selector.selectedKeys().iterator(); - while (it.hasNext()) { - SelectionKey key = it.next(); - it.remove(); - processKeyOperation(key); - } - } - } - } - - /** - * Prunes the registered streams by discarding any stale ones. - * - * @return number of remaining streams - */ - public synchronized int pruneStaleStreams() { - for (MessageStream<M> stream : streams) { - if (stream.isStale()) { - stream.close(); - } - } - return streams.size(); - } - -} diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/Message.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/Message.java deleted file mode 100644 index c1a339e0..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/Message.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -/** - * Representation of a message transferred via {@link MessageStream}. - */ -public interface Message { - - /** - * Gets the message length in bytes. - * - * @return number of bytes - */ - int length(); - -} diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/MessageStream.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/MessageStream.java deleted file mode 100644 index a19e8aac..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/MessageStream.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import org.onlab.util.Counter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.ByteChannel; -import java.nio.channels.SelectionKey; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static java.lang.System.currentTimeMillis; -import static java.nio.ByteBuffer.allocateDirect; - -/** - * Bi-directional message stream for transferring messages to & from the - * network via two byte buffers. - * - * @param <M> message type - */ -public abstract class MessageStream<M extends Message> { - - protected Logger log = LoggerFactory.getLogger(getClass()); - - private final IOLoop<M, ?> loop; - private final ByteChannel channel; - private final int maxIdleMillis; - - private final ByteBuffer inbound; - private ByteBuffer outbound; - private SelectionKey key; - - private volatile boolean closed = false; - private volatile boolean writePending; - private volatile boolean writeOccurred; - - private Exception ioError; - private long lastActiveTime; - - private final Counter bytesIn = new Counter(); - private final Counter messagesIn = new Counter(); - private final Counter bytesOut = new Counter(); - private final Counter messagesOut = new Counter(); - - /** - * Creates a message stream associated with the specified IO loop and - * backed by the given byte channel. - * - * @param loop IO loop - * @param byteChannel backing byte channel - * @param bufferSize size of the backing byte buffers - * @param maxIdleMillis maximum number of millis the stream can be idle - * before it will be closed - */ - protected MessageStream(IOLoop<M, ?> loop, ByteChannel byteChannel, - int bufferSize, int maxIdleMillis) { - this.loop = checkNotNull(loop, "Loop cannot be null"); - this.channel = checkNotNull(byteChannel, "Byte channel cannot be null"); - - checkArgument(maxIdleMillis > 0, "Idle time must be positive"); - this.maxIdleMillis = maxIdleMillis; - - inbound = allocateDirect(bufferSize); - outbound = allocateDirect(bufferSize); - } - - /** - * Gets a single message from the specified byte buffer; this is - * to be done without manipulating the buffer via flip, reset or clear. - * - * @param buffer byte buffer - * @return read message or null if there are not enough bytes to read - * a complete message - */ - protected abstract M read(ByteBuffer buffer); - - /** - * Puts the specified message into the specified byte buffer; this is - * to be done without manipulating the buffer via flip, reset or clear. - * - * @param message message to be write into the buffer - * @param buffer byte buffer - */ - protected abstract void write(M message, ByteBuffer buffer); - - /** - * Closes the message buffer. - */ - public void close() { - synchronized (this) { - if (closed) { - return; - } - closed = true; - } - - bytesIn.freeze(); - bytesOut.freeze(); - messagesIn.freeze(); - messagesOut.freeze(); - - loop.removeStream(this); - if (key != null) { - try { - key.cancel(); - key.channel().close(); - } catch (IOException e) { - log.warn("Unable to close stream", e); - } - } - } - - /** - * Indicates whether this buffer has been closed. - * - * @return true if this stream has been closed - */ - public synchronized boolean isClosed() { - return closed; - } - - /** - * Returns the stream IO selection key. - * - * @return socket channel registration selection key - */ - public SelectionKey key() { - return key; - } - - /** - * Binds the selection key to be used for driving IO operations on the stream. - * - * @param key IO selection key - */ - public void setKey(SelectionKey key) { - this.key = key; - this.lastActiveTime = currentTimeMillis(); - } - - /** - * Returns the IO loop to which this stream is bound. - * - * @return I/O loop used to drive this stream - */ - public IOLoop<M, ?> loop() { - return loop; - } - - /** - * Indicates whether the any prior IO encountered an error. - * - * @return true if a write failed - */ - public boolean hadError() { - return ioError != null; - } - - /** - * Gets the prior IO error, if one occurred. - * - * @return IO error; null if none occurred - */ - public Exception getError() { - return ioError; - } - - /** - * Reads, without blocking, a list of messages from the stream. - * The list will be empty if there were not messages pending. - * - * @return list of messages or null if backing channel has been closed - * @throws IOException if messages could not be read - */ - public List<M> read() throws IOException { - try { - int read = channel.read(inbound); - if (read != -1) { - // Read the messages one-by-one and add them to the list. - List<M> messages = new ArrayList<>(); - M message; - inbound.flip(); - while ((message = read(inbound)) != null) { - messages.add(message); - messagesIn.add(1); - bytesIn.add(message.length()); - } - inbound.compact(); - - // Mark the stream with current time to indicate liveness. - lastActiveTime = currentTimeMillis(); - return messages; - } - return null; - - } catch (Exception e) { - throw new IOException("Unable to read messages", e); - } - } - - /** - * Writes the specified list of messages to the stream. - * - * @param messages list of messages to write - * @throws IOException if error occurred while writing the data - */ - public void write(List<M> messages) throws IOException { - synchronized (this) { - // First write all messages. - for (M m : messages) { - append(m); - } - flushUnlessAlreadyPlanningTo(); - } - } - - /** - * Writes the given message to the stream. - * - * @param message message to write - * @throws IOException if error occurred while writing the data - */ - public void write(M message) throws IOException { - synchronized (this) { - append(message); - flushUnlessAlreadyPlanningTo(); - } - } - - // Appends the specified message into the internal buffer, growing the - // buffer if required. - private void append(M message) { - // If the buffer does not have sufficient length double it. - while (outbound.remaining() < message.length()) { - doubleSize(); - } - write(message, outbound); - messagesOut.add(1); - bytesOut.add(message.length()); - } - - // Forces a flush, unless one is planned already. - private void flushUnlessAlreadyPlanningTo() throws IOException { - if (!writeOccurred && !writePending) { - flush(); - } - } - - /** - * Flushes any pending writes. - * - * @throws IOException if flush failed - */ - public void flush() throws IOException { - synchronized (this) { - if (!writeOccurred && !writePending) { - outbound.flip(); - try { - channel.write(outbound); - } catch (IOException e) { - if (!closed && !Objects.equals(e.getMessage(), "Broken pipe")) { - log.warn("Unable to write data", e); - ioError = e; - } - } - lastActiveTime = currentTimeMillis(); - writeOccurred = true; - writePending = outbound.hasRemaining(); - outbound.compact(); - } - } - } - - /** - * Indicates whether the stream has bytes to be written to the channel. - * - * @return true if there are bytes to be written - */ - boolean isWritePending() { - synchronized (this) { - return writePending; - } - } - - - /** - * Indicates whether data has been written but not flushed yet. - * - * @return true if flush is required - */ - boolean isFlushRequired() { - synchronized (this) { - return outbound.position() > 0; - } - } - - /** - * Attempts to flush data, internal stream state and channel availability - * permitting. Invoked by the driver I/O loop during handling of writable - * selection key. - * <p> - * Resets the internal state flags {@code writeOccurred} and - * {@code writePending}. - * </p> - * @throws IOException if implicit flush failed - */ - void flushIfPossible() throws IOException { - synchronized (this) { - writePending = false; - writeOccurred = false; - if (outbound.position() > 0) { - flush(); - } - } - key.interestOps(SelectionKey.OP_READ); - } - - /** - * Attempts to flush data, internal stream state and channel availability - * permitting and if other writes are not pending. Invoked by the driver - * I/O loop prior to entering select wait. Resets the internal - * {@code writeOccurred} state flag. - * - * @throws IOException if implicit flush failed - */ - void flushIfWriteNotPending() throws IOException { - synchronized (this) { - writeOccurred = false; - if (!writePending && outbound.position() > 0) { - flush(); - } - } - if (isWritePending()) { - key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); - } - } - - /** - * Doubles the size of the outbound buffer. - */ - private void doubleSize() { - ByteBuffer newBuffer = allocateDirect(outbound.capacity() * 2); - outbound.flip(); - newBuffer.put(outbound); - outbound = newBuffer; - } - - /** - * Returns the maximum number of milliseconds the stream is allowed - * without any read/write operations. - * - * @return number if millis of permissible idle time - */ - protected int maxIdleMillis() { - return maxIdleMillis; - } - - - /** - * Returns true if the given stream has gone stale. - * - * @return true if the stream is stale - */ - boolean isStale() { - return currentTimeMillis() - lastActiveTime > maxIdleMillis() && key != null; - } - - /** - * Returns the inbound bytes counter. - * - * @return inbound bytes counter - */ - public Counter bytesIn() { - return bytesIn; - } - - /** - * Returns the outbound bytes counter. - * - * @return outbound bytes counter - */ - public Counter bytesOut() { - return bytesOut; - } - - /** - * Returns the inbound messages counter. - * - * @return inbound messages counter - */ - public Counter messagesIn() { - return messagesIn; - } - - /** - * Returns the outbound messages counter. - * - * @return outbound messages counter - */ - public Counter messagesOut() { - return messagesOut; - } - -} diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/SelectorLoop.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/SelectorLoop.java deleted file mode 100644 index 95a9b61e..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/SelectorLoop.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.nio.channels.Selector; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.lang.System.currentTimeMillis; - -/** - * Abstraction of an I/O processing loop based on an NIO selector. - */ -public abstract class SelectorLoop implements Runnable { - - protected final Logger log = LoggerFactory.getLogger(getClass()); - - /** - * Selector used by this loop to pace the I/O operations. - */ - protected final Selector selector; - - /** - * Selection operations timeout; specified in millis. - */ - protected long selectTimeout; - - /** - * Retains the error that caused the loop to exit prematurely. - */ - private Throwable error; - - // State indicator - private enum State { STARTING, STARTED, STOPPING, STOPPED }; - private volatile State state = State.STOPPED; - - /** - * Creates a new selector loop with the given selection timeout. - * - * @param selectTimeout selection timeout; specified in millis - * @throws IOException if the backing selector cannot be opened - */ - public SelectorLoop(long selectTimeout) throws IOException { - checkArgument(selectTimeout > 0, "Timeout must be positive"); - this.selectTimeout = selectTimeout; - this.selector = openSelector(); - } - - /** - * Opens a new selector for the use by the loop. - * - * @return newly open selector - * @throws IOException if the backing selector cannot be opened - */ - protected Selector openSelector() throws IOException { - return Selector.open(); - } - - /** - * Indicates that the loop is marked to run. - * @return true if the loop is marked to run - */ - protected boolean isRunning() { - return state == State.STARTED || state == State.STARTING; - } - - /** - * Returns the error, if there was one, that caused the loop to terminate - * prematurely. - * - * @return error or null if there was none - */ - public Throwable getError() { - return error; - } - - /** - * Contains the body of the I/O selector loop. - * - * @throws IOException if an error is encountered while selecting I/O - */ - protected abstract void loop() throws IOException; - - @Override - public void run() { - error = null; - state = State.STARTING; - try { - loop(); - } catch (Exception e) { - error = e; - log.error("Loop aborted", e); - } - notifyDone(); - } - - /** - * Notifies observers waiting for loop to become ready. - */ - protected synchronized void notifyReady() { - state = State.STARTED; - notifyAll(); - } - - /** - * Triggers loop shutdown. - */ - public void shutdown() { - // Mark the loop as no longer running and wake up the selector. - state = State.STOPPING; - selector.wakeup(); - } - - /** - * Notifies observers waiting for loop to fully stop. - */ - private synchronized void notifyDone() { - state = State.STOPPED; - notifyAll(); - } - - /** - * Waits for the loop execution to start. - * - * @param timeout number of milliseconds to wait - * @return true if loop started in time - */ - public final synchronized boolean awaitStart(long timeout) { - long max = currentTimeMillis() + timeout; - while (state != State.STARTED && (currentTimeMillis() < max)) { - try { - wait(timeout); - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted", e); - } - } - return state == State.STARTED; - } - - /** - * Waits for the loop execution to stop. - * - * @param timeout number of milliseconds to wait - * @return true if loop finished in time - */ - public final synchronized boolean awaitStop(long timeout) { - long max = currentTimeMillis() + timeout; - while (state != State.STOPPED && (currentTimeMillis() < max)) { - try { - wait(timeout); - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted", e); - } - } - return state == State.STOPPED; - } - - -} diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/package-info.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/package-info.java deleted file mode 100644 index 0d58b568..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Mechanism to transfer messages over network using IO loop and - * message stream, backed by NIO byte buffers. - */ -package org.onlab.nio; diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultIOLoop.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultIOLoop.java deleted file mode 100644 index 0d977929..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultIOLoop.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.nio.service; - -import java.io.IOException; -import java.nio.channels.ByteChannel; -import java.nio.channels.SelectionKey; -import java.util.List; -import java.util.function.Consumer; - -import org.onlab.nio.IOLoop; -import org.onlab.nio.MessageStream; - -/** - * IOLoop for transporting DefaultMessages. - */ -public class DefaultIOLoop extends IOLoop<DefaultMessage, DefaultMessageStream> { - - public static final int SELECT_TIMEOUT_MILLIS = 500; - private static final int MAX_IDLE_TIMEOUT_MILLIS = 1000; - private static final int BUFFER_SIZE = 1024 * 1024; - private final Consumer<DefaultMessage> consumer; - - public DefaultIOLoop(Consumer<DefaultMessage> consumer) throws IOException { - this(SELECT_TIMEOUT_MILLIS, consumer); - } - - public DefaultIOLoop(long timeout, Consumer<DefaultMessage> consumer) throws IOException { - super(timeout); - this.consumer = consumer; - } - - @Override - protected DefaultMessageStream createStream(ByteChannel byteChannel) { - return new DefaultMessageStream(this, byteChannel, BUFFER_SIZE, MAX_IDLE_TIMEOUT_MILLIS); - } - - @Override - protected void processMessages(List<DefaultMessage> messages, MessageStream<DefaultMessage> stream) { - messages.forEach(consumer); - } - - @Override - protected void connect(SelectionKey key) throws IOException { - DefaultMessageStream stream = (DefaultMessageStream) key.attachment(); - try { - super.connect(key); - stream.connected(); - } catch (Exception e) { - stream.connectFailed(e); - } - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultMessage.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultMessage.java deleted file mode 100644 index 591d49b3..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultMessage.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.nio.service; - -import static com.google.common.base.Preconditions.checkNotNull; - -import org.onlab.nio.AbstractMessage; -import org.onlab.packet.IpAddress; -import org.onlab.util.ByteArraySizeHashPrinter; -import org.onosproject.store.cluster.messaging.Endpoint; - -import com.google.common.base.Charsets; -import com.google.common.base.MoreObjects; - -/** - * Default message. - */ -public class DefaultMessage extends AbstractMessage { - - private long id; - private Endpoint sender; - private String type; - private byte[] payload; - - /** - * Creates a new message with the specified data. - * - * @param id message id - * @param type message type - * @param sender sender endpoint - * @param payload message payload - */ - DefaultMessage(long id, Endpoint sender, String type, byte[] payload) { - this.id = id; - this.type = checkNotNull(type, "Type cannot be null"); - this.sender = checkNotNull(sender, "Sender cannot be null"); - this.payload = checkNotNull(payload, "Payload cannot be null"); - - byte[] messageTypeBytes = type.getBytes(Charsets.UTF_8); - IpAddress senderIp = sender.host(); - byte[] ipOctets = senderIp.toOctets(); - - length = 25 + ipOctets.length + messageTypeBytes.length + payload.length; - } - - /** - * Returns message id. - * - * @return message id - */ - public long id() { - return id; - } - - /** - * Returns message sender. - * - * @return message sender - */ - public Endpoint sender() { - return sender; - } - - /** - * Returns message type. - * - * @return message type - */ - public String type() { - return type; - } - - /** - * Returns message payload. - * - * @return payload - */ - public byte[] payload() { - return payload; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("id", id) - .add("type", type) - .add("sender", sender) - .add("payload", ByteArraySizeHashPrinter.of(payload)) - .toString(); - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultMessageStream.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultMessageStream.java deleted file mode 100644 index a7dd3c04..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/DefaultMessageStream.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.nio.service; - -import java.nio.ByteBuffer; -import java.nio.channels.ByteChannel; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicInteger; - -import org.onlab.nio.IOLoop; -import org.onlab.nio.MessageStream; -import org.onlab.packet.IpAddress; -import org.onlab.packet.IpAddress.Version; -import org.onosproject.store.cluster.messaging.Endpoint; - -import com.google.common.base.Charsets; - -/** - * Default bi-directional message stream for transferring messages to & from the - * network via two byte buffers. - */ -public class DefaultMessageStream extends MessageStream<DefaultMessage> { - - private final CompletableFuture<Void> connectFuture = new CompletableFuture<>(); - - public DefaultMessageStream( - IOLoop<DefaultMessage, ?> loop, - ByteChannel byteChannel, - int bufferSize, - int maxIdleMillis) { - super(loop, byteChannel, bufferSize, maxIdleMillis); - } - - public CompletableFuture<DefaultMessageStream> connectedFuture() { - return connectFuture.thenApply(v -> this); - } - - private final AtomicInteger messageLength = new AtomicInteger(-1); - - @Override - protected DefaultMessage read(ByteBuffer buffer) { - if (messageLength.get() == -1) { - // check if we can read the message length. - if (buffer.remaining() < Integer.BYTES) { - return null; - } else { - messageLength.set(buffer.getInt()); - } - } - - if (buffer.remaining() < messageLength.get()) { - return null; - } - - long id = buffer.getLong(); - Version ipVersion = buffer.get() == 0x0 ? Version.INET : Version.INET6; - byte[] octects = new byte[IpAddress.byteLength(ipVersion)]; - buffer.get(octects); - IpAddress senderIp = IpAddress.valueOf(ipVersion, octects); - int senderPort = buffer.getInt(); - int messageTypeByteLength = buffer.getInt(); - byte[] messageTypeBytes = new byte[messageTypeByteLength]; - buffer.get(messageTypeBytes); - String messageType = new String(messageTypeBytes, Charsets.UTF_8); - int payloadLength = buffer.getInt(); - byte[] payloadBytes = new byte[payloadLength]; - buffer.get(payloadBytes); - - // reset for next message - messageLength.set(-1); - - return new DefaultMessage(id, new Endpoint(senderIp, senderPort), messageType, payloadBytes); - } - - @Override - protected void write(DefaultMessage message, ByteBuffer buffer) { - Endpoint sender = message.sender(); - byte[] messageTypeBytes = message.type().getBytes(Charsets.UTF_8); - IpAddress senderIp = sender.host(); - byte[] ipOctets = senderIp.toOctets(); - byte[] payload = message.payload(); - - int messageLength = 21 + ipOctets.length + messageTypeBytes.length + payload.length; - - buffer.putInt(messageLength); - - buffer.putLong(message.id()); - - if (senderIp.version() == Version.INET) { - buffer.put((byte) 0x0); - } else { - buffer.put((byte) 0x1); - } - buffer.put(ipOctets); - - // write sender port - buffer.putInt(sender.port()); - - // write length of message type - buffer.putInt(messageTypeBytes.length); - - // write message type bytes - buffer.put(messageTypeBytes); - - // write payload length - buffer.putInt(payload.length); - - // write payload. - buffer.put(payload); - } - - /** - * Callback invoked when the stream is successfully connected. - */ - public void connected() { - connectFuture.complete(null); - } - - /** - * Callback invoked when the stream fails to connect. - * @param cause failure cause - */ - public void connectFailed(Throwable cause) { - connectFuture.completeExceptionally(cause); - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/IOLoopMessaging.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/IOLoopMessaging.java deleted file mode 100644 index c195d160..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/IOLoopMessaging.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.nio.service; - -import static org.onlab.util.Tools.groupedThreads; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; -import java.util.function.Function; - -import org.apache.commons.pool.KeyedPoolableObjectFactory; -import org.apache.commons.pool.impl.GenericKeyedObjectPool; -import org.onlab.nio.AcceptorLoop; -import org.onlab.nio.SelectorLoop; -import org.onosproject.store.cluster.messaging.Endpoint; -import org.onosproject.store.cluster.messaging.MessagingService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalListener; -import com.google.common.cache.RemovalNotification; -import com.google.common.collect.Lists; - -/** - * MessagingService implementation based on IOLoop. - */ -public class IOLoopMessaging implements MessagingService { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private static final String REPLY_MESSAGE_TYPE = "ONOS_REQUEST_REPLY"; - - static final long TIMEOUT = 1000; - - static final boolean SO_NO_DELAY = false; - static final int SO_SEND_BUFFER_SIZE = 128 * 1024; - static final int SO_RCV_BUFFER_SIZE = 128 * 1024; - - private static final int NUM_WORKERS = 8; - - private AcceptorLoop acceptorLoop; - private final ExecutorService acceptorThreadPool = - Executors.newSingleThreadExecutor(groupedThreads("onos/nio/messaging", "acceptor")); - private final ExecutorService ioThreadPool = - Executors.newFixedThreadPool(NUM_WORKERS, groupedThreads("onos/nio/messaging", "io-loop-worker-%d")); - - private final List<DefaultIOLoop> ioLoops = Lists.newArrayList(); - - private int lastWorker = -1; - - private final AtomicBoolean started = new AtomicBoolean(false); - private Endpoint localEp; - - private GenericKeyedObjectPool<Endpoint, DefaultMessageStream> streams = - new GenericKeyedObjectPool<>(new DefaultMessageStreamFactory()); - - private final ConcurrentMap<String, Consumer<DefaultMessage>> handlers = new ConcurrentHashMap<>(); - private final AtomicLong messageIdGenerator = new AtomicLong(0); - private final Cache<Long, CompletableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder() - .removalListener(new RemovalListener<Long, CompletableFuture<byte[]>>() { - @Override - public void onRemoval(RemovalNotification<Long, CompletableFuture<byte[]>> entry) { - if (entry.wasEvicted()) { - entry.getValue().completeExceptionally(new TimeoutException("Timedout waiting for reply")); - } - } - }) - .build(); - - /** - * Activates IO Loops. - * - * @param localEp local end-point - * @throws IOException is activation fails - */ - public void start(Endpoint localEp) throws IOException { - if (started.get()) { - log.warn("IOMessaging is already running at {}", localEp); - return; - } - this.localEp = localEp; - streams.setLifo(false); - this.acceptorLoop = new DefaultAcceptorLoop(new InetSocketAddress(localEp.host().toString(), localEp.port())); - - for (int i = 0; i < NUM_WORKERS; i++) { - ioLoops.add(new DefaultIOLoop(this::dispatchLocally)); - } - - ioLoops.forEach(ioThreadPool::execute); - acceptorThreadPool.execute(acceptorLoop); - ioLoops.forEach(loop -> loop.awaitStart(TIMEOUT)); - acceptorLoop.awaitStart(TIMEOUT); - started.set(true); - } - - /** - * Shuts down IO loops. - */ - public void stop() { - if (started.get()) { - ioLoops.forEach(SelectorLoop::shutdown); - acceptorLoop.shutdown(); - ioThreadPool.shutdown(); - acceptorThreadPool.shutdown(); - started.set(false); - } - } - - - @Override - public CompletableFuture<Void> sendAsync(Endpoint ep, String type, byte[] payload) { - DefaultMessage message = new DefaultMessage( - messageIdGenerator.incrementAndGet(), - localEp, - type, - payload); - return sendAsync(ep, message); - } - - protected CompletableFuture<Void> sendAsync(Endpoint ep, DefaultMessage message) { - CompletableFuture<Void> future = new CompletableFuture<>(); - if (ep.equals(localEp)) { - dispatchLocally(message); - future.complete(null); - return future; - } - - DefaultMessageStream stream = null; - try { - stream = streams.borrowObject(ep); - stream.write(message); - future.complete(null); - } catch (Exception e) { - future.completeExceptionally(e); - } finally { - try { - streams.returnObject(ep, stream); - } catch (Exception e) { - log.warn("Failed to return stream to pool"); - } - } - return future; - } - - @Override - public CompletableFuture<byte[]> sendAndReceive( - Endpoint ep, - String type, - byte[] payload) { - CompletableFuture<byte[]> response = new CompletableFuture<>(); - Long messageId = messageIdGenerator.incrementAndGet(); - responseFutures.put(messageId, response); - DefaultMessage message = new DefaultMessage(messageId, localEp, type, payload); - try { - sendAsync(ep, message); - } catch (Exception e) { - responseFutures.invalidate(messageId); - response.completeExceptionally(e); - } - return response; - } - - @Override - public void registerHandler(String type, Consumer<byte[]> handler, Executor executor) { - handlers.put(type, message -> executor.execute(() -> handler.accept(message.payload()))); - } - - @Override - public void registerHandler(String type, Function<byte[], byte[]> handler, Executor executor) { - handlers.put(type, message -> executor.execute(() -> { - byte[] responsePayload = handler.apply(message.payload()); - if (responsePayload != null) { - DefaultMessage response = new DefaultMessage(message.id(), - localEp, - REPLY_MESSAGE_TYPE, - responsePayload); - sendAsync(message.sender(), response).whenComplete((result, error) -> { - log.debug("Failed to respond", error); - }); - } - })); - } - - @Override - public void registerHandler(String type, Function<byte[], CompletableFuture<byte[]>> handler) { - handlers.put(type, message -> { - handler.apply(message.payload()).whenComplete((result, error) -> { - if (error == null) { - DefaultMessage response = new DefaultMessage(message.id(), - localEp, - REPLY_MESSAGE_TYPE, - result); - sendAsync(message.sender(), response).whenComplete((r, e) -> { - if (e != null) { - log.debug("Failed to respond", e); - } - }); - } - }); - }); - } - - @Override - public void unregisterHandler(String type) { - handlers.remove(type); - } - - protected void dispatchLocally(DefaultMessage message) { - String type = message.type(); - if (REPLY_MESSAGE_TYPE.equals(type)) { - try { - CompletableFuture<byte[]> futureResponse = - responseFutures.getIfPresent(message.id()); - if (futureResponse != null) { - futureResponse.complete(message.payload()); - } else { - log.warn("Received a reply for message id:[{}]. " - + " from {}. But was unable to locate the" - + " request handle", message.id(), message.sender()); - } - } finally { - responseFutures.invalidate(message.id()); - } - return; - } - Consumer<DefaultMessage> handler = handlers.get(type); - if (handler != null) { - handler.accept(message); - } else { - log.debug("No handler registered for {}", type); - } - } - - // Get the next worker to which a client should be assigned - private synchronized DefaultIOLoop nextWorker() { - lastWorker = (lastWorker + 1) % NUM_WORKERS; - return ioLoops.get(lastWorker); - } - - /** - * Initiates open connection request and registers the pending socket - * channel with the given IO loop. - * - * @param loop loop with which the channel should be registered - * @throws java.io.IOException if the socket could not be open or connected - */ - private DefaultMessageStream createConnection(Endpoint ep, DefaultIOLoop loop) throws IOException { - SocketAddress sa = new InetSocketAddress(ep.host().toString(), ep.port()); - SocketChannel ch = SocketChannel.open(); - ch.configureBlocking(false); - DefaultMessageStream stream = loop.connectStream(ch); - ch.connect(sa); - return stream; - } - - // Loop for accepting client connections - private class DefaultAcceptorLoop extends AcceptorLoop { - - public DefaultAcceptorLoop(SocketAddress address) throws IOException { - super(DefaultIOLoop.SELECT_TIMEOUT_MILLIS, address); - } - - @Override - protected void acceptConnection(ServerSocketChannel channel) throws IOException { - SocketChannel sc = channel.accept(); - sc.configureBlocking(false); - - Socket so = sc.socket(); - so.setTcpNoDelay(SO_NO_DELAY); - so.setReceiveBufferSize(SO_RCV_BUFFER_SIZE); - so.setSendBufferSize(SO_SEND_BUFFER_SIZE); - - nextWorker().acceptStream(sc); - } - } - - private class DefaultMessageStreamFactory implements KeyedPoolableObjectFactory<Endpoint, DefaultMessageStream> { - - @Override - public void activateObject(Endpoint endpoint, DefaultMessageStream stream) throws Exception { - } - - @Override - public void destroyObject(Endpoint ep, DefaultMessageStream stream) throws Exception { - stream.close(); - } - - @Override - public DefaultMessageStream makeObject(Endpoint ep) throws Exception { - DefaultMessageStream stream = createConnection(ep, nextWorker()).connectedFuture().get(); - log.info("Established a new connection to {}", ep); - return stream; - } - - @Override - public void passivateObject(Endpoint ep, DefaultMessageStream stream) throws Exception { - } - - @Override - public boolean validateObject(Endpoint ep, DefaultMessageStream stream) { - return stream.isClosed(); - } - } -} diff --git a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/package-info.java b/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/package-info.java deleted file mode 100644 index 399a2b95..00000000 --- a/framework/src/onos/utils/nio/src/main/java/org/onlab/nio/service/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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. - */ - -/** - * Assembly for sending and receiving messages using the I/O loop mechanism. - */ -package org.onlab.nio.service;
\ No newline at end of file diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/AbstractLoopTest.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/AbstractLoopTest.java deleted file mode 100644 index 2b4a85cd..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/AbstractLoopTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import org.junit.Before; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; - -import static java.util.concurrent.Executors.newSingleThreadExecutor; -import static org.junit.Assert.fail; -import static org.onlab.util.Tools.namedThreads; - -/** - * Base class for various NIO loop unit tests. - */ -public abstract class AbstractLoopTest { - - protected static final long MAX_MS_WAIT = 1500; - - /** Block on specified countdown latch. Return when countdown reaches - * zero, or fail the test if the {@value #MAX_MS_WAIT} ms timeout expires. - * - * @param latch the latch - * @param label an identifying label - */ - protected void waitForLatch(CountDownLatch latch, String label) { - try { - boolean ok = latch.await(MAX_MS_WAIT, TimeUnit.MILLISECONDS); - if (!ok) { - fail("Latch await timeout! [" + label + "]"); - } - } catch (InterruptedException e) { - System.out.println("Latch interrupt [" + label + "] : " + e); - fail("Unexpected interrupt"); - } - } - - protected ExecutorService exec; - - @Before - public void setUp() { - exec = newSingleThreadExecutor(namedThreads("test")); - } - -} diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/AcceptorLoopTest.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/AcceptorLoopTest.java deleted file mode 100644 index f04a0126..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/AcceptorLoopTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.nio; - -import org.junit.Test; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.channels.ServerSocketChannel; -import java.util.concurrent.CountDownLatch; - -import static org.junit.Assert.assertEquals; -import static org.onlab.junit.TestTools.delay; - -/** - * Unit tests for AcceptLoop. - */ -public class AcceptorLoopTest extends AbstractLoopTest { - - private static final int PICK_EPHEMERAL = 0; - - private static final SocketAddress SOCK_ADDR = new InetSocketAddress("127.0.0.1", PICK_EPHEMERAL); - - private static class MyAcceptLoop extends AcceptorLoop { - private final CountDownLatch loopStarted = new CountDownLatch(1); - private final CountDownLatch loopFinished = new CountDownLatch(1); - private final CountDownLatch runDone = new CountDownLatch(1); - private final CountDownLatch ceaseLatch = new CountDownLatch(1); - - private int acceptCount = 0; - - MyAcceptLoop() throws IOException { - super(500, SOCK_ADDR); - } - - @Override - protected void acceptConnection(ServerSocketChannel ssc) throws IOException { - acceptCount++; - } - - @Override - public void loop() throws IOException { - loopStarted.countDown(); - super.loop(); - loopFinished.countDown(); - } - - @Override - public void run() { - super.run(); - runDone.countDown(); - } - - @Override - public void shutdown() { - super.shutdown(); - ceaseLatch.countDown(); - } - } - - @Test - public void basic() throws IOException { - MyAcceptLoop myAccLoop = new MyAcceptLoop(); - AcceptorLoop accLoop = myAccLoop; - exec.execute(accLoop); - waitForLatch(myAccLoop.loopStarted, "loopStarted"); - delay(200); // take a quick nap - accLoop.shutdown(); - waitForLatch(myAccLoop.loopFinished, "loopFinished"); - waitForLatch(myAccLoop.runDone, "runDone"); - assertEquals(0, myAccLoop.acceptCount); - } -} diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopIntegrationTest.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopIntegrationTest.java deleted file mode 100644 index f42c8dc5..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopIntegrationTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import java.net.InetAddress; -import java.util.Random; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.onlab.junit.TestTools.delay; - -/** - * Integration test for the select, accept and IO loops. - */ -public class IOLoopIntegrationTest { - - private static final int THREADS = 6; - private static final int TIMEOUT = 60; - private static final int MESSAGE_LENGTH = 128; - - private static final int MILLION = 1000000; - private static final int MSG_COUNT = 40 * MILLION; - - @Before - public void warmUp() throws Exception { - Logger.getLogger("").setLevel(Level.SEVERE); - try { - runTest(MILLION, MESSAGE_LENGTH, 15); - } catch (Throwable e) { - System.err.println("Failed warmup but moving on."); - e.printStackTrace(); - } - } - - // TODO: this test can not pass in some environments, need to be improved - @Ignore - @Test - public void basic() throws Exception { - runTest(MILLION, MESSAGE_LENGTH, TIMEOUT); - } - - public void longHaul() throws Exception { - runTest(MSG_COUNT, MESSAGE_LENGTH, TIMEOUT); - } - - private void runTest(int count, int size, int timeout) throws Exception { - // Use a random port to prevent conflicts. - int port = IOLoopTestServer.PORT + new Random().nextInt(100); - - InetAddress ip = InetAddress.getLoopbackAddress(); - IOLoopTestServer server = new IOLoopTestServer(ip, THREADS, size, port); - IOLoopTestClient client = new IOLoopTestClient(ip, THREADS, count, size, port); - - server.start(); - client.start(); - delay(100); // Pause to allow loops to get going - - client.await(timeout); - client.report(); - - server.stop(); - server.report(); - } - -} diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopTestClient.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopTestClient.java deleted file mode 100644 index acc9a08f..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopTestClient.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import com.google.common.collect.Lists; -import org.onlab.util.Counter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.channels.ByteChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.SocketChannel; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import static java.lang.String.format; -import static java.lang.System.nanoTime; -import static java.lang.System.out; -import static org.onlab.nio.IOLoopTestServer.PORT; -import static org.onlab.util.Tools.delay; -import static org.onlab.util.Tools.namedThreads; - -/** - * Auxiliary test fixture to measure speed of NIO-based channels. - */ -public class IOLoopTestClient { - - private static Logger log = LoggerFactory.getLogger(IOLoopTestClient.class); - - private final InetAddress ip; - private final int port; - private final int msgCount; - private final int msgLength; - - private final List<CustomIOLoop> iloops = new ArrayList<>(); - private final ExecutorService ipool; - private final ExecutorService wpool; - - Counter messages; - Counter bytes; - long latencyTotal = 0; - long latencyCount = 0; - - - /** - * Main entry point to launch the client. - * - * @param args command-line arguments - * @throws java.io.IOException if unable to connect to server - * @throws InterruptedException if latch wait gets interrupted - * @throws java.util.concurrent.ExecutionException if wait gets interrupted - * @throws java.util.concurrent.TimeoutException if timeout occurred while waiting for completion - */ - public static void main(String[] args) - throws IOException, InterruptedException, ExecutionException, TimeoutException { - startStandalone(args); - - System.exit(0); - } - - /** - * Starts a standalone IO loop test client. - * - * @param args command-line arguments - */ - public static void startStandalone(String[] args) - throws IOException, InterruptedException, ExecutionException, TimeoutException { - InetAddress ip = InetAddress.getByName(args.length > 0 ? args[0] : "127.0.0.1"); - int wc = args.length > 1 ? Integer.parseInt(args[1]) : 6; - int mc = args.length > 2 ? Integer.parseInt(args[2]) : 50 * 1000000; - int ml = args.length > 3 ? Integer.parseInt(args[3]) : 128; - int to = args.length > 4 ? Integer.parseInt(args[4]) : 60; - - log.info("Setting up client with {} workers sending {} {}-byte messages to {} server... ", - wc, mc, ml, ip); - IOLoopTestClient client = new IOLoopTestClient(ip, wc, mc, ml, PORT); - - client.start(); - delay(500); - - client.await(to); - client.report(); - } - - /** - * Creates a speed client. - * - * @param ip ip address of server - * @param wc worker count - * @param mc message count to send per client - * @param ml message length in bytes - * @param port socket port - * @throws java.io.IOException if unable to create IO loops - */ - public IOLoopTestClient(InetAddress ip, int wc, int mc, int ml, int port) throws IOException { - this.ip = ip; - this.port = port; - this.msgCount = mc; - this.msgLength = ml; - this.wpool = Executors.newFixedThreadPool(wc, namedThreads("worker")); - this.ipool = Executors.newFixedThreadPool(wc, namedThreads("io-loop")); - - for (int i = 0; i < wc; i++) { - iloops.add(new CustomIOLoop()); - } - } - - /** - * Starts the client workers. - * - * @throws java.io.IOException if unable to open connection - */ - public void start() throws IOException { - messages = new Counter(); - bytes = new Counter(); - - // First start up all the IO loops - for (CustomIOLoop l : iloops) { - ipool.execute(l); - } - - // Wait for all of them to get going - for (CustomIOLoop l : iloops) { - l.awaitStart(1000); - } - - // ... and Next open all connections; one-per-loop - for (CustomIOLoop l : iloops) { - openConnection(l); - } - } - - - /** - * Initiates open connection request and registers the pending socket - * channel with the given IO loop. - * - * @param loop loop with which the channel should be registered - * @throws java.io.IOException if the socket could not be open or connected - */ - private void openConnection(CustomIOLoop loop) throws IOException { - SocketAddress sa = new InetSocketAddress(ip, port); - SocketChannel ch = SocketChannel.open(); - ch.configureBlocking(false); - loop.connectStream(ch); - ch.connect(sa); - } - - - /** - * Waits for the client workers to complete. - * - * @param secs timeout in seconds - * @throws java.util.concurrent.ExecutionException if execution failed - * @throws InterruptedException if interrupt occurred while waiting - * @throws java.util.concurrent.TimeoutException if timeout occurred - */ - public void await(int secs) throws InterruptedException, - ExecutionException, TimeoutException { - for (CustomIOLoop l : iloops) { - if (l.worker.task != null) { - l.worker.task.get(secs, TimeUnit.SECONDS); - latencyTotal += l.latencyTotal; - latencyCount += l.latencyCount; - } - } - messages.freeze(); - bytes.freeze(); - } - - /** - * Reports on the accumulated throughput and latency. - */ - public void report() { - DecimalFormat f = new DecimalFormat("#,##0"); - out.println(format("Client: %s messages; %s bytes; %s mps; %s MBs; %s ns latency", - f.format(messages.total()), f.format(bytes.total()), - f.format(messages.throughput()), - f.format(bytes.throughput() / (1024 * msgLength)), - f.format(latencyTotal / latencyCount))); - } - - - // Loop for transfer of fixed-length messages - private class CustomIOLoop extends IOLoop<TestMessage, TestMessageStream> { - - Worker worker = new Worker(); - long latencyTotal = 0; - long latencyCount = 0; - - - public CustomIOLoop() throws IOException { - super(500); - } - - - @Override - protected TestMessageStream createStream(ByteChannel channel) { - return new TestMessageStream(msgLength, channel, this); - } - - @Override - protected synchronized void removeStream(MessageStream<TestMessage> stream) { - super.removeStream(stream); - messages.add(stream.messagesIn().total()); - bytes.add(stream.bytesIn().total()); - stream.messagesOut().reset(); - stream.bytesOut().reset(); - } - - @Override - protected void processMessages(List<TestMessage> messages, - MessageStream<TestMessage> stream) { - for (TestMessage message : messages) { - // TODO: summarize latency data better - latencyTotal += nanoTime() - message.requestorTime(); - latencyCount++; - } - worker.release(messages.size()); - } - - @Override - protected void connect(SelectionKey key) throws IOException { - super.connect(key); - TestMessageStream b = (TestMessageStream) key.attachment(); - Worker w = ((CustomIOLoop) b.loop()).worker; - w.pump(b); - } - - } - - /** - * Auxiliary worker to connect and pump batched messages using blocking I/O. - */ - private class Worker implements Runnable { - - private static final int BATCH_SIZE = 50; - private static final int PERMITS = 2 * BATCH_SIZE; - - private TestMessageStream stream; - private FutureTask<Worker> task; - - // Stuff to throttle pump - private final Semaphore semaphore = new Semaphore(PERMITS); - private int msgWritten; - - void pump(TestMessageStream stream) { - this.stream = stream; - task = new FutureTask<>(this, this); - wpool.execute(task); - } - - @Override - public void run() { - try { - log.info("Worker started..."); - - while (msgWritten < msgCount) { - int size = Math.min(BATCH_SIZE, msgCount - msgWritten); - writeBatch(size); - msgWritten += size; - } - - // Now try to get all the permits back before sending poison pill - semaphore.acquireUninterruptibly(PERMITS); - stream.close(); - - log.info("Worker done..."); - - } catch (IOException e) { - log.error("Worker unable to perform I/O", e); - } - } - - - private void writeBatch(int size) throws IOException { - // Build a batch of messages - List<TestMessage> batch = Lists.newArrayListWithCapacity(size); - for (int i = 0; i < size; i++) { - batch.add(new TestMessage(msgLength, nanoTime(), 0, stream.padding())); - } - acquire(size); - stream.write(batch); - } - - - // Release permits based on the specified number of message credits - private void release(int permits) { - semaphore.release(permits); - } - - // Acquire permit for a single batch - private void acquire(int permits) { - semaphore.acquireUninterruptibly(permits); - } - - } - -} diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopTestServer.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopTestServer.java deleted file mode 100644 index d5ce5f39..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/IOLoopTestServer.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import com.google.common.collect.Lists; -import org.onlab.util.Counter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.nio.channels.ByteChannel; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import static java.lang.String.format; -import static java.lang.System.out; -import static org.onlab.util.Tools.delay; -import static org.onlab.util.Tools.namedThreads; - -/** - * Auxiliary test fixture to measure speed of NIO-based channels. - */ -public class IOLoopTestServer { - - private static Logger log = LoggerFactory.getLogger(IOLoopTestServer.class); - - private static final int PRUNE_FREQUENCY = 1000; - - static final int PORT = 9876; - static final long TIMEOUT = 1000; - - static final boolean SO_NO_DELAY = false; - static final int SO_SEND_BUFFER_SIZE = 128 * 1024; - static final int SO_RCV_BUFFER_SIZE = 128 * 1024; - - static final DecimalFormat FORMAT = new DecimalFormat("#,##0"); - - private final AcceptorLoop aloop; - private final ExecutorService apool = Executors.newSingleThreadExecutor(namedThreads("accept")); - - private final List<CustomIOLoop> iloops = new ArrayList<>(); - private final ExecutorService ipool; - - private final int workerCount; - private final int msgLength; - private int lastWorker = -1; - - Counter messages; - Counter bytes; - - /** - * Main entry point to launch the server. - * - * @param args command-line arguments - * @throws java.io.IOException if unable to crate IO loops - */ - public static void main(String[] args) throws IOException { - startStandalone(args); - System.exit(0); - } - - /** - * Starts a standalone IO loop test server. - * - * @param args command-line arguments - */ - public static void startStandalone(String[] args) throws IOException { - InetAddress ip = InetAddress.getByName(args.length > 0 ? args[0] : "127.0.0.1"); - int wc = args.length > 1 ? Integer.parseInt(args[1]) : 6; - int ml = args.length > 2 ? Integer.parseInt(args[2]) : 128; - - log.info("Setting up the server with {} workers, {} byte messages on {}... ", - wc, ml, ip); - IOLoopTestServer server = new IOLoopTestServer(ip, wc, ml, PORT); - server.start(); - - // Start pruning clients and keep going until their number goes to 0. - int remaining = -1; - while (remaining == -1 || remaining > 0) { - delay(PRUNE_FREQUENCY); - int r = server.prune(); - remaining = remaining == -1 && r == 0 ? remaining : r; - } - server.stop(); - } - - /** - * Creates a speed server. - * - * @param ip optional ip of the adapter where to bind - * @param wc worker count - * @param ml message length in bytes - * @param port listen port - * @throws java.io.IOException if unable to create IO loops - */ - public IOLoopTestServer(InetAddress ip, int wc, int ml, int port) throws IOException { - this.workerCount = wc; - this.msgLength = ml; - this.ipool = Executors.newFixedThreadPool(workerCount, namedThreads("io-loop")); - - this.aloop = new CustomAcceptLoop(new InetSocketAddress(ip, port)); - for (int i = 0; i < workerCount; i++) { - iloops.add(new CustomIOLoop()); - } - } - - /** - * Start the server IO loops and kicks off throughput tracking. - */ - public void start() { - messages = new Counter(); - bytes = new Counter(); - - for (CustomIOLoop l : iloops) { - ipool.execute(l); - } - apool.execute(aloop); - - for (CustomIOLoop l : iloops) { - l.awaitStart(TIMEOUT); - } - aloop.awaitStart(TIMEOUT); - } - - /** - * Stop the server IO loops and freezes throughput tracking. - */ - public void stop() { - aloop.shutdown(); - for (CustomIOLoop l : iloops) { - l.shutdown(); - } - - for (CustomIOLoop l : iloops) { - l.awaitStop(TIMEOUT); - } - aloop.awaitStop(TIMEOUT); - - messages.freeze(); - bytes.freeze(); - } - - /** - * Reports on the accumulated throughput and latency. - */ - public void report() { - DecimalFormat f = new DecimalFormat("#,##0"); - out.println(format("Server: %s messages; %s bytes; %s mps; %s MBs", - f.format(messages.total()), f.format(bytes.total()), - f.format(messages.throughput()), - f.format(bytes.throughput() / (1024 * msgLength)))); - } - - /** - * Prunes the IO loops of stale message buffers. - * - * @return number of remaining IO loops among all workers. - */ - public int prune() { - int count = 0; - for (CustomIOLoop l : iloops) { - count += l.pruneStaleStreams(); - } - return count; - } - - // Get the next worker to which a client should be assigned - private synchronized CustomIOLoop nextWorker() { - lastWorker = (lastWorker + 1) % workerCount; - return iloops.get(lastWorker); - } - - // Loop for transfer of fixed-length messages - private class CustomIOLoop extends IOLoop<TestMessage, TestMessageStream> { - - public CustomIOLoop() throws IOException { - super(500); - } - - @Override - protected TestMessageStream createStream(ByteChannel channel) { - return new TestMessageStream(msgLength, channel, this); - } - - @Override - protected void removeStream(MessageStream<TestMessage> stream) { - super.removeStream(stream); - messages.add(stream.messagesIn().total()); - bytes.add(stream.bytesIn().total()); - } - - @Override - protected void processMessages(List<TestMessage> messages, - MessageStream<TestMessage> stream) { - try { - stream.write(createResponses(messages)); - } catch (IOException e) { - log.error("Unable to echo messages", e); - } - } - - private List<TestMessage> createResponses(List<TestMessage> messages) { - List<TestMessage> responses = Lists.newArrayListWithCapacity(messages.size()); - for (TestMessage message : messages) { - responses.add(new TestMessage(message.length(), message.requestorTime(), - System.nanoTime(), message.padding())); - } - return responses; - } - } - - // Loop for accepting client connections - private class CustomAcceptLoop extends AcceptorLoop { - - public CustomAcceptLoop(SocketAddress address) throws IOException { - super(500, address); - } - - @Override - protected void acceptConnection(ServerSocketChannel channel) throws IOException { - SocketChannel sc = channel.accept(); - sc.configureBlocking(false); - - Socket so = sc.socket(); - so.setTcpNoDelay(SO_NO_DELAY); - so.setReceiveBufferSize(SO_RCV_BUFFER_SIZE); - so.setSendBufferSize(SO_SEND_BUFFER_SIZE); - - nextWorker().acceptStream(sc); - log.info("Connected client"); - } - } - -} diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/MessageStreamTest.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/MessageStreamTest.java deleted file mode 100644 index 9965d389..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/MessageStreamTest.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.ByteChannel; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.spi.SelectorProvider; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -/** - * Tests of the message message stream implementation. - */ -public class MessageStreamTest { - - private static final int SIZE = 64; - private static final int BIG_SIZE = 32 * 1024; - - private TestMessage message; - - private TestIOLoop loop; - private TestByteChannel channel; - private TestMessageStream stream; - private TestKey key; - - @Before - public void setUp() throws IOException { - loop = new TestIOLoop(); - channel = new TestByteChannel(); - key = new TestKey(channel); - stream = loop.createStream(channel); - stream.setKey(key); - stream.setNonStrict(); - message = new TestMessage(SIZE, 0, 0, stream.padding()); - } - - @After - public void tearDown() { - loop.shutdown(); - stream.close(); - } - - // Validates the state of the message stream - private void validate(boolean wp, boolean fr, int read, int written) { - assertEquals(wp, stream.isWritePending()); - assertEquals(fr, stream.isFlushRequired()); - assertEquals(read, channel.readBytes); - assertEquals(written, channel.writtenBytes); - } - - @Test - public void endOfStream() throws IOException { - channel.close(); - List<TestMessage> messages = stream.read(); - assertNull(messages); - } - - @Test - public void bufferGrowth() throws IOException { - // Create a stream for big messages and test the growth. - stream = new TestMessageStream(BIG_SIZE, channel, loop); - TestMessage bigMessage = new TestMessage(BIG_SIZE, 0, 0, stream.padding()); - - stream.write(bigMessage); - stream.write(bigMessage); - stream.write(bigMessage); - stream.write(bigMessage); - stream.write(bigMessage); - } - - @Test - public void discardBeforeKey() { - // Create a stream that does not yet have the key set and discard it. - stream = loop.createStream(channel); - assertNull(stream.key()); - stream.close(); - // There is not key, so nothing to check; we just expect no problem. - } - - @Test - public void bufferedRead() throws IOException { - channel.bytesToRead = SIZE + 4; - List<TestMessage> messages = stream.read(); - assertEquals(1, messages.size()); - validate(false, false, SIZE + 4, 0); - - channel.bytesToRead = SIZE - 4; - messages = stream.read(); - assertEquals(1, messages.size()); - validate(false, false, SIZE * 2, 0); - } - - @Test - public void bufferedWrite() throws IOException { - validate(false, false, 0, 0); - - // First write is immediate... - stream.write(message); - validate(false, false, 0, SIZE); - - // Second and third get buffered... - stream.write(message); - validate(false, true, 0, SIZE); - stream.write(message); - validate(false, true, 0, SIZE); - - // Reset write, which will flush if needed; the next write is again buffered - stream.flushIfWriteNotPending(); - validate(false, false, 0, SIZE * 3); - stream.write(message); - validate(false, true, 0, SIZE * 3); - - // Select reset, which will flush if needed; the next write is again buffered - stream.flushIfPossible(); - validate(false, false, 0, SIZE * 4); - stream.write(message); - validate(false, true, 0, SIZE * 4); - stream.flush(); - validate(false, true, 0, SIZE * 4); - } - - @Test - public void bufferedWriteList() throws IOException { - validate(false, false, 0, 0); - - // First write is immediate... - List<TestMessage> messages = new ArrayList<>(); - messages.add(message); - messages.add(message); - messages.add(message); - messages.add(message); - - stream.write(messages); - validate(false, false, 0, SIZE * 4); - - stream.write(messages); - validate(false, true, 0, SIZE * 4); - - stream.flushIfPossible(); - validate(false, false, 0, SIZE * 8); - } - - @Test - public void bufferedPartialWrite() throws IOException { - validate(false, false, 0, 0); - - // First write is immediate... - stream.write(message); - validate(false, false, 0, SIZE); - - // Tell test channel to accept only half. - channel.bytesToWrite = SIZE / 2; - - // Second and third get buffered... - stream.write(message); - validate(false, true, 0, SIZE); - stream.flushIfPossible(); - validate(true, true, 0, SIZE + SIZE / 2); - } - - @Test - public void bufferedPartialWrite2() throws IOException { - validate(false, false, 0, 0); - - // First write is immediate... - stream.write(message); - validate(false, false, 0, SIZE); - - // Tell test channel to accept only half. - channel.bytesToWrite = SIZE / 2; - - // Second and third get buffered... - stream.write(message); - validate(false, true, 0, SIZE); - stream.flushIfWriteNotPending(); - validate(true, true, 0, SIZE + SIZE / 2); - } - - @Test - public void bufferedReadWrite() throws IOException { - channel.bytesToRead = SIZE + 4; - List<TestMessage> messages = stream.read(); - assertEquals(1, messages.size()); - validate(false, false, SIZE + 4, 0); - - stream.write(message); - validate(false, false, SIZE + 4, SIZE); - - channel.bytesToRead = SIZE - 4; - messages = stream.read(); - assertEquals(1, messages.size()); - validate(false, false, SIZE * 2, SIZE); - } - - // Fake IO driver loop - private static class TestIOLoop extends IOLoop<TestMessage, TestMessageStream> { - - public TestIOLoop() throws IOException { - super(500); - } - - @Override - protected TestMessageStream createStream(ByteChannel channel) { - return new TestMessageStream(SIZE, channel, this); - } - - @Override - protected void processMessages(List<TestMessage> messages, - MessageStream<TestMessage> stream) { - } - - } - - // Byte channel test fixture - private static class TestByteChannel extends SelectableChannel implements ByteChannel { - - private static final int BUFFER_LENGTH = 1024; - byte[] bytes = new byte[BUFFER_LENGTH]; - int bytesToWrite = BUFFER_LENGTH; - int bytesToRead = BUFFER_LENGTH; - int writtenBytes = 0; - int readBytes = 0; - - @Override - public int read(ByteBuffer dst) throws IOException { - int l = Math.min(dst.remaining(), bytesToRead); - if (bytesToRead > 0) { - readBytes += l; - dst.put(bytes, 0, l); - } - return l; - } - - @Override - public int write(ByteBuffer src) throws IOException { - int l = Math.min(src.remaining(), bytesToWrite); - writtenBytes += l; - src.get(bytes, 0, l); - return l; - } - - @Override - public Object blockingLock() { - return null; - } - - @Override - public SelectableChannel configureBlocking(boolean arg0) throws IOException { - return null; - } - - @Override - public boolean isBlocking() { - return false; - } - - @Override - public boolean isRegistered() { - return false; - } - - @Override - public SelectionKey keyFor(Selector arg0) { - return null; - } - - @Override - public SelectorProvider provider() { - return null; - } - - @Override - public SelectionKey register(Selector arg0, int arg1, Object arg2) - throws ClosedChannelException { - return null; - } - - @Override - public int validOps() { - return 0; - } - - @Override - protected void implCloseChannel() throws IOException { - bytesToRead = -1; - } - - } - - // Selection key text fixture - private static class TestKey extends SelectionKey { - - private SelectableChannel channel; - - public TestKey(TestByteChannel channel) { - this.channel = channel; - } - - @Override - public void cancel() { - } - - @Override - public SelectableChannel channel() { - return channel; - } - - @Override - public int interestOps() { - return 0; - } - - @Override - public SelectionKey interestOps(int ops) { - return null; - } - - @Override - public boolean isValid() { - return true; - } - - @Override - public int readyOps() { - return 0; - } - - @Override - public Selector selector() { - return null; - } - } - -} diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/MockSelector.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/MockSelector.java deleted file mode 100644 index cf5b2bb9..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/MockSelector.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import java.io.IOException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.spi.AbstractSelectableChannel; -import java.nio.channels.spi.AbstractSelector; -import java.util.Set; - -/** - * A selector instrumented for unit tests. - */ -public class MockSelector extends AbstractSelector { - - int wakeUpCount = 0; - - /** - * Creates a mock selector, specifying null as the SelectorProvider. - */ - public MockSelector() { - super(null); - } - - @Override - public String toString() { - return "{MockSelector: wake=" + wakeUpCount + "}"; - } - - @Override - protected void implCloseSelector() throws IOException { - } - - @Override - protected SelectionKey register(AbstractSelectableChannel ch, int ops, - Object att) { - return null; - } - - @Override - public Set<SelectionKey> keys() { - return null; - } - - @Override - public Set<SelectionKey> selectedKeys() { - return null; - } - - @Override - public int selectNow() throws IOException { - return 0; - } - - @Override - public int select(long timeout) throws IOException { - return 0; - } - - @Override - public int select() throws IOException { - return 0; - } - - @Override - public Selector wakeup() { - wakeUpCount++; - return null; - } - -} diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/TestMessage.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/TestMessage.java deleted file mode 100644 index 825479b5..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/TestMessage.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Test message for measuring rate and round-trip latency. - */ -public class TestMessage extends AbstractMessage { - - private final byte[] padding; - - private final long requestorTime; - private final long responderTime; - - /** - * Creates a new message with the specified data. - * - * @param requestorTime requester time - * @param responderTime responder time - * @param padding message padding - */ - TestMessage(int length, long requestorTime, long responderTime, byte[] padding) { - this.length = length; - this.requestorTime = requestorTime; - this.responderTime = responderTime; - this.padding = checkNotNull(padding, "Padding cannot be null"); - } - - public long requestorTime() { - return requestorTime; - } - - public long responderTime() { - return responderTime; - } - - public byte[] padding() { - return padding; - } - -} diff --git a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/TestMessageStream.java b/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/TestMessageStream.java deleted file mode 100644 index fc86beb9..00000000 --- a/framework/src/onos/utils/nio/src/test/java/org/onlab/nio/TestMessageStream.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.nio; - -import java.nio.ByteBuffer; -import java.nio.channels.ByteChannel; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; - -/** - * Fixed-length message transfer buffer. - */ -public class TestMessageStream extends MessageStream<TestMessage> { - - private static final String E_WRONG_LEN = "Illegal message length: "; - private static final long START_TAG = 0xfeedcafedeaddeedL; - private static final long END_TAG = 0xbeadcafedeaddeedL; - private static final int META_LENGTH = 40; - - private final int length; - private boolean isStrict = true; - - public TestMessageStream(int length, ByteChannel ch, IOLoop<TestMessage, ?> loop) { - super(loop, ch, 64 * 1024, 500); - checkArgument(length >= META_LENGTH, "Length must be greater than header length of 40"); - this.length = length; - } - - void setNonStrict() { - isStrict = false; - } - - @Override - protected TestMessage read(ByteBuffer rb) { - if (rb.remaining() < length) { - return null; - } - - long startTag = rb.getLong(); - if (isStrict) { - checkState(startTag == START_TAG, "Incorrect message start"); - } - - long size = rb.getLong(); - long requestorTime = rb.getLong(); - long responderTime = rb.getLong(); - byte[] padding = padding(); - rb.get(padding); - - long endTag = rb.getLong(); - if (isStrict) { - checkState(endTag == END_TAG, "Incorrect message end"); - } - - return new TestMessage((int) size, requestorTime, responderTime, padding); - } - - @Override - protected void write(TestMessage message, ByteBuffer wb) { - if (message.length() != length) { - throw new IllegalArgumentException(E_WRONG_LEN + message.length()); - } - - wb.putLong(START_TAG); - wb.putLong(message.length()); - wb.putLong(message.requestorTime()); - wb.putLong(message.responderTime()); - wb.put(message.padding(), 0, length - META_LENGTH); - wb.putLong(END_TAG); - } - - public byte[] padding() { - return new byte[length - META_LENGTH]; - } -} diff --git a/framework/src/onos/utils/osgi/pom.xml b/framework/src/onos/utils/osgi/pom.xml deleted file mode 100644 index 25690cab..00000000 --- a/framework/src/onos/utils/osgi/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-osgi</artifactId> - <packaging>bundle</packaging> - - <description>ON.Lab OSGI utilities</description> - - <dependencies> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.core</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-junit</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - -</project> diff --git a/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/DefaultServiceDirectory.java b/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/DefaultServiceDirectory.java deleted file mode 100644 index b3421485..00000000 --- a/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/DefaultServiceDirectory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.osgi; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.ServiceReference; - -/** - * Default implementation of the service directory using OSGi framework utilities. - */ -public class DefaultServiceDirectory implements ServiceDirectory { - - /** - * Returns the reference to the implementation of the specified service. - * - * @param serviceClass service class - * @param <T> type of service - * @return service implementation - */ - public static <T> T getService(Class<T> serviceClass) { - BundleContext bc = FrameworkUtil.getBundle(serviceClass).getBundleContext(); - if (bc != null) { - ServiceReference<T> reference = bc.getServiceReference(serviceClass); - if (reference != null) { - T impl = bc.getService(reference); - if (impl != null) { - return impl; - } - } - } - throw new ServiceNotFoundException("Service " + serviceClass.getName() + " not found"); - } - - @Override - public <T> T get(Class<T> serviceClass) { - return getService(serviceClass); - } - -} diff --git a/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/ServiceDirectory.java b/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/ServiceDirectory.java deleted file mode 100644 index f9ffed74..00000000 --- a/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/ServiceDirectory.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.osgi; - -/** - * Simple abstraction of a service directory where service implementations can - * be found by the class name of the interfaces they provide. - */ -public interface ServiceDirectory { - - /** - * Returns implementation of the specified service class. - * - * @param serviceClass service class - * @param <T> type of service - * @return implementation class - * @throws ServiceNotFoundException if no implementation found - */ - <T> T get(Class<T> serviceClass); - -} diff --git a/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/ServiceNotFoundException.java b/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/ServiceNotFoundException.java deleted file mode 100644 index 8b14227e..00000000 --- a/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/ServiceNotFoundException.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.osgi; - -/** - * Represents condition where some service is not found or not available. - */ -public class ServiceNotFoundException extends RuntimeException { - - /** - * Creates a new exception with no message. - */ - public ServiceNotFoundException() { - } - - /** - * Creates a new exception with the supplied message. - * @param message error message - */ - public ServiceNotFoundException(String message) { - super(message); - } - - /** - * Creates a new exception with the supplied message and cause. - * @param message error message - * @param cause cause of the error - */ - public ServiceNotFoundException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/package-info.java b/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/package-info.java deleted file mode 100644 index 289c60a4..00000000 --- a/framework/src/onos/utils/osgi/src/main/java/org/onlab/osgi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Facilities for building testable components in OSGi independent fashion. - */ -package org.onlab.osgi; diff --git a/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/ComponentContextAdapter.java b/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/ComponentContextAdapter.java deleted file mode 100644 index b8718c3c..00000000 --- a/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/ComponentContextAdapter.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.osgi; - -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.service.component.ComponentContext; -import org.osgi.service.component.ComponentInstance; - -import java.util.Dictionary; -import java.util.Enumeration; - -/** - * Adapter implementation of OSGI component context. - */ -public class ComponentContextAdapter implements ComponentContext { - private static class MockDictionary extends Dictionary { - - @Override - public int size() { - return 0; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public Enumeration keys() { - return null; - } - - @Override - public Enumeration elements() { - return null; - } - - @Override - public Object get(Object key) { - return null; - } - - @Override - public Object put(Object key, Object value) { - return null; - } - - @Override - public Object remove(Object key) { - return null; - } - } - - @Override - public Dictionary getProperties() { - return new MockDictionary(); - } - - @Override - public Object locateService(String name) { - return null; - } - - @Override - public Object locateService(String name, ServiceReference reference) { - return null; - } - - @Override - public Object[] locateServices(String name) { - return new Object[0]; - } - - @Override - public BundleContext getBundleContext() { - return null; - } - - @Override - public Bundle getUsingBundle() { - return null; - } - - @Override - public ComponentInstance getComponentInstance() { - return null; - } - - @Override - public void enableComponent(String name) { - - } - - @Override - public void disableComponent(String name) { - - } - - @Override - public ServiceReference getServiceReference() { - return null; - } -} diff --git a/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/TestServiceDirectory.java b/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/TestServiceDirectory.java deleted file mode 100644 index 08089ada..00000000 --- a/framework/src/onos/utils/osgi/src/test/java/org/onlab/osgi/TestServiceDirectory.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014-2015 Open Networking Laboratory - * - * 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.onlab.osgi; - -import com.google.common.collect.ClassToInstanceMap; -import com.google.common.collect.MutableClassToInstanceMap; - -/** - * Service directory implementation suitable for testing. - */ -@SuppressWarnings("unchecked") -public class TestServiceDirectory implements ServiceDirectory { - - private ClassToInstanceMap<Object> services = MutableClassToInstanceMap.create(); - - @Override - public <T> T get(Class<T> serviceClass) { - return services.getInstance(serviceClass); - } - - /** - * Adds a new service to the directory. - * - * @param serviceClass service class - * @param service service instance - * @return self - */ - public TestServiceDirectory add(Class serviceClass, Object service) { - services.putInstance(serviceClass, service); - return this; - } - -} diff --git a/framework/src/onos/utils/pom.xml b/framework/src/onos/utils/pom.xml deleted file mode 100644 index d3cd5a5b..00000000 --- a/framework/src/onos/utils/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onos</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-utils</artifactId> - <packaging>pom</packaging> - - <description>Domain agnostic ON.Lab utilities</description> - - <modules> - <module>junit</module> - <module>misc</module> - <module>netty</module> - <module>nio</module> - <module>osgi</module> - <module>rest</module> - <module>thirdparty</module> - <module>stc</module> - <module>jdvue</module> - <module>jnc</module> - <module>catalyst</module> <!-- FIXME publish and remove before release --> - </modules> - - <dependencies> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava</artifactId> - </dependency> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.compendium</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - </plugin> - </plugins> - </build> - -</project> diff --git a/framework/src/onos/utils/rest/pom.xml b/framework/src/onos/utils/rest/pom.xml deleted file mode 100644 index 80a2e32e..00000000 --- a/framework/src/onos/utils/rest/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-rest</artifactId> - <packaging>bundle</packaging> - - <description>ON.Lab JAX-RS utilities</description> - - <dependencies> - <dependency> - <groupId>com.sun.jersey.jersey-test-framework</groupId> - <artifactId>jersey-test-framework-core</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>com.sun.jersey.jersey-test-framework</groupId> - <artifactId>jersey-test-framework-grizzly2</artifactId> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-osgi</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - -</project> diff --git a/framework/src/onos/utils/rest/src/main/java/org/onlab/rest/BaseResource.java b/framework/src/onos/utils/rest/src/main/java/org/onlab/rest/BaseResource.java deleted file mode 100644 index 50b4d0f1..00000000 --- a/framework/src/onos/utils/rest/src/main/java/org/onlab/rest/BaseResource.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.rest; - -import org.onlab.osgi.DefaultServiceDirectory; -import org.onlab.osgi.ServiceDirectory; - -import javax.ws.rs.core.Response; - -/** - * Base abstraction of a JAX-RS resource. - */ -public abstract class BaseResource { - - private static ServiceDirectory services = new DefaultServiceDirectory(); - - /** - * Sets alternate service directory to be used for lookups. - * <p> - * Intended to ease unit testing and not intended for use in production. - * </p> - * - * @param serviceDirectory alternate service directory - */ - public static void setServiceDirectory(ServiceDirectory serviceDirectory) { - services = serviceDirectory; - } - - /** - * Returns reference to the specified service implementation. - * - * @param service service class - * @param <T> type of service - * @return service implementation - */ - public <T> T get(Class<T> service) { - return services.get(service); - } - - protected static Response.ResponseBuilder ok(Object obj) { - return Response.ok(obj); - } - -} diff --git a/framework/src/onos/utils/rest/src/main/java/org/onlab/rest/package-info.java b/framework/src/onos/utils/rest/src/main/java/org/onlab/rest/package-info.java deleted file mode 100644 index 4f9c523d..00000000 --- a/framework/src/onos/utils/rest/src/main/java/org/onlab/rest/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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. - */ - -/** - * Facilities for building JAX-RS web resources. - */ -package org.onlab.rest; diff --git a/framework/src/onos/utils/stc/bin/stc b/framework/src/onos/utils/stc/bin/stc deleted file mode 100755 index 541ddcbb..00000000 --- a/framework/src/onos/utils/stc/bin/stc +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -#------------------------------------------------------------------------------- -# System Test Coordinator -#------------------------------------------------------------------------------- - -STC_ROOT=${STC_ROOT:-$(dirname $0)/..} -cd $STC_ROOT -VER=1.4.0-rc1 - -PATH=$PWD/bin:$PATH - -java -jar target/onlab-stc-$VER.jar "$@" diff --git a/framework/src/onos/utils/stc/bin/stc-launcher b/framework/src/onos/utils/stc/bin/stc-launcher deleted file mode 100755 index 0d56017e..00000000 --- a/framework/src/onos/utils/stc/bin/stc-launcher +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -#------------------------------------------------------------------------------- -# System Test Coordinator process launcher -#------------------------------------------------------------------------------- - -env=$1 && shift -cwd=$1 && shift - -if [ $env != "-" ]; then - [ ! -f $env ] && echo "$env file not found" && exit 1 - source $env -fi - -if [ $cwd != "-" ]; then - [ ! -d $cwd ] && echo "$cwd directory not found" && exit 1 - cd $cwd -fi - -"$@" 2>&1 diff --git a/framework/src/onos/utils/stc/pom.xml b/framework/src/onos/utils/stc/pom.xml deleted file mode 100644 index 568aa74c..00000000 --- a/framework/src/onos/utils/stc/pom.xml +++ /dev/null @@ -1,122 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-stc</artifactId> - <packaging>jar</packaging> - - <description>System Test Coordinator</description> - - <dependencies> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-misc</artifactId> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>onlab-junit</artifactId> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>commons-configuration</groupId> - <artifactId>commons-configuration</artifactId> - </dependency> - - <dependency> - <groupId>commons-collections</groupId> - <artifactId>commons-collections</artifactId> - </dependency> - - <dependency> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-databind</artifactId> - <version>2.4.2</version> - <scope>compile</scope> - </dependency> - <dependency> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-annotations</artifactId> - <version>2.4.2</version> - <scope>compile</scope> - </dependency> - - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>8.1.17.v20150415</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-servlet</artifactId> - <version>8.1.17.v20150415</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-websocket</artifactId> - <version>8.1.17.v20150415</version> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-shade-plugin</artifactId> - <version>2.3</version> - <configuration> - <transformers> - <transformer - implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> - <mainClass>org.onlab.stc.Main - </mainClass> - </transformer> - </transformers> - <filters> - <filter> - <artifact>*:*</artifact> - <excludes> - <exclude>META-INF/*.SF</exclude> - <exclude>META-INF/*.DSA</exclude> - <exclude>META-INF/*.RSA</exclude> - </excludes> - </filter> - </filters> - </configuration> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>shade</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - -</project> diff --git a/framework/src/onos/utils/stc/sample/scenario.xml b/framework/src/onos/utils/stc/sample/scenario.xml deleted file mode 100644 index 8cee6319..00000000 --- a/framework/src/onos/utils/stc/sample/scenario.xml +++ /dev/null @@ -1,20 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<scenario name="sample" description="Sample Test Scenario"> - <step name="alpha" exec="/bin/ls -l"/> - <step name="beta" exec="/bin/ls -lF"/> - <step name="gamma" exec="/bin/ls" requires="alpha,beta"/> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java deleted file mode 100644 index 919cbd5b..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Compiler.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.apache.commons.configuration.HierarchicalConfiguration; -import org.onlab.graph.DepthFirstSearch; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.Preconditions.*; -import static com.google.common.base.Strings.isNullOrEmpty; -import static org.onlab.graph.DepthFirstSearch.EdgeType.BACK_EDGE; -import static org.onlab.graph.GraphPathSearch.ALL_PATHS; -import static org.onlab.stc.Scenario.loadScenario; - -/** - * Entity responsible for loading a scenario and producing a redy-to-execute - * process flow graph. - */ -public class Compiler { - - private static final String DEFAULT_LOG_DIR = "${WORKSPACE}/tmp/stc/"; - - private static final String IMPORT = "import"; - private static final String GROUP = "group"; - private static final String STEP = "step"; - private static final String PARALLEL = "parallel"; - private static final String SEQUENTIAL = "sequential"; - private static final String DEPENDENCY = "dependency"; - - private static final String LOG_DIR = "[@logDir]"; - private static final String NAME = "[@name]"; - private static final String COMMAND = "[@exec]"; - private static final String ENV = "[@env]"; - private static final String CWD = "[@cwd]"; - private static final String REQUIRES = "[@requires]"; - private static final String IF = "[@if]"; - private static final String UNLESS = "[@unless]"; - private static final String VAR = "[@var]"; - private static final String STARTS = "[@starts]"; - private static final String ENDS = "[@ends]"; - private static final String FILE = "[@file]"; - private static final String NAMESPACE = "[@namespace]"; - - static final String PROP_START = "${"; - static final String PROP_END = "}"; - - private static final String HASH = "#"; - private static final String HASH_PREV = "#-1"; - - private final Scenario scenario; - - private final Map<String, Step> steps = Maps.newHashMap(); - private final Map<String, Step> inactiveSteps = Maps.newHashMap(); - private final Map<String, String> requirements = Maps.newHashMap(); - private final Set<Dependency> dependencies = Sets.newHashSet(); - private final List<Integer> clonables = Lists.newArrayList(); - - private ProcessFlow processFlow; - private File logDir; - - private String previous = null; - private String pfx = ""; - private boolean debugOn = System.getenv("debug") != null; - - /** - * Creates a new compiler for the specified scenario. - * - * @param scenario scenario to be compiled - */ - public Compiler(Scenario scenario) { - this.scenario = scenario; - } - - /** - * Returns the scenario being compiled. - * - * @return test scenario - */ - public Scenario scenario() { - return scenario; - } - - /** - * Compiles the specified scenario to produce a final process flow graph. - */ - public void compile() { - compile(scenario.definition(), null, null); - compileRequirements(); - - // Produce the process flow - processFlow = new ProcessFlow(ImmutableSet.copyOf(steps.values()), - ImmutableSet.copyOf(dependencies)); - - scanForCycles(); - - // Extract the log directory if there was one specified - String defaultPath = DEFAULT_LOG_DIR + scenario.name(); - String path = scenario.definition().getString(LOG_DIR, defaultPath); - logDir = new File(expand(path)); - } - - /** - * Returns the step with the specified name. - * - * @param name step or group name - * @return test step or group - */ - public Step getStep(String name) { - return steps.get(name); - } - - /** - * Returns the process flow generated from this scenario definition. - * - * @return process flow as a graph - */ - public ProcessFlow processFlow() { - return processFlow; - } - - /** - * Returns the log directory where scenario logs should be kept. - * - * @return scenario logs directory - */ - public File logDir() { - return logDir; - } - - /** - * Recursively elaborates this definition to produce a final process flow graph. - * - * @param cfg hierarchical definition - * @param namespace optional namespace - * @param parentGroup optional parent group - */ - private void compile(HierarchicalConfiguration cfg, - String namespace, Group parentGroup) { - String opfx = pfx; - pfx = pfx + ">"; - print("pfx=%s namespace=%s", pfx, namespace); - - // Scan all imports - cfg.configurationsAt(IMPORT) - .forEach(c -> processImport(c, namespace, parentGroup)); - - // Scan all steps - cfg.configurationsAt(STEP) - .forEach(c -> processStep(c, namespace, parentGroup)); - - // Scan all groups - cfg.configurationsAt(GROUP) - .forEach(c -> processGroup(c, namespace, parentGroup)); - - // Scan all parallel groups - cfg.configurationsAt(PARALLEL) - .forEach(c -> processParallelGroup(c, namespace, parentGroup)); - - // Scan all sequential groups - cfg.configurationsAt(SEQUENTIAL) - .forEach(c -> processSequentialGroup(c, namespace, parentGroup)); - - // Scan all dependencies - cfg.configurationsAt(DEPENDENCY) - .forEach(c -> processDependency(c, namespace)); - - pfx = opfx; - } - - /** - * Compiles requirements for all steps and groups accrued during the - * overall compilation process. - */ - private void compileRequirements() { - requirements.forEach((name, requires) -> - compileRequirements(getStep(name), requires)); - } - - private void compileRequirements(Step src, String requires) { - split(requires).forEach(n -> { - boolean isSoft = n.startsWith("~"); - String name = n.replaceFirst("^~", ""); - Step dst = getStep(name); - if (dst != null) { - dependencies.add(new Dependency(src, dst, isSoft)); - } - }); - } - - /** - * Processes an import directive. - * - * @param cfg hierarchical definition - * @param namespace optional namespace - * @param parentGroup optional parent group - */ - private void processImport(HierarchicalConfiguration cfg, - String namespace, Group parentGroup) { - String file = checkNotNull(expand(cfg.getString(FILE)), - "Import directive must specify 'file'"); - String newNamespace = expand(prefix(cfg.getString(NAMESPACE), namespace)); - print("import file=%s namespace=%s", file, newNamespace); - try { - Scenario importScenario = loadScenario(new FileInputStream(file)); - compile(importScenario.definition(), newNamespace, parentGroup); - } catch (IOException e) { - throw new IllegalArgumentException("Unable to import scenario", e); - } - } - - /** - * Processes a step directive. - * - * @param cfg hierarchical definition - * @param namespace optional namespace - * @param parentGroup optional parent group - */ - private void processStep(HierarchicalConfiguration cfg, - String namespace, Group parentGroup) { - String name = expand(prefix(cfg.getString(NAME), namespace)); - String command = expand(cfg.getString(COMMAND, parentGroup != null ? parentGroup.command() : null), true); - String env = expand(cfg.getString(ENV, parentGroup != null ? parentGroup.env() : null)); - String cwd = expand(cfg.getString(CWD, parentGroup != null ? parentGroup.cwd() : null)); - - print("step name=%s command=%s env=%s cwd=%s", name, command, env, cwd); - Step step = new Step(name, command, env, cwd, parentGroup); - registerStep(step, cfg, namespace, parentGroup); - } - - /** - * Processes a group directive. - * - * @param cfg hierarchical definition - * @param namespace optional namespace - * @param parentGroup optional parent group - */ - private void processGroup(HierarchicalConfiguration cfg, - String namespace, Group parentGroup) { - String name = expand(prefix(cfg.getString(NAME), namespace)); - String command = expand(cfg.getString(COMMAND, parentGroup != null ? parentGroup.command() : null), true); - String env = expand(cfg.getString(ENV, parentGroup != null ? parentGroup.env() : null)); - String cwd = expand(cfg.getString(CWD, parentGroup != null ? parentGroup.cwd() : null)); - - print("group name=%s command=%s env=%s cwd=%s", name, command, env, cwd); - Group group = new Group(name, command, env, cwd, parentGroup); - if (registerStep(group, cfg, namespace, parentGroup)) { - compile(cfg, namespace, group); - } - } - - /** - * Registers the specified step or group. - * - * @param step step or group - * @param cfg hierarchical definition - * @param namespace optional namespace - * @param parentGroup optional parent group - * @return true of the step or group was registered as active - */ - private boolean registerStep(Step step, HierarchicalConfiguration cfg, - String namespace, Group parentGroup) { - checkState(!steps.containsKey(step.name()), "Step %s already exists", step.name()); - String ifClause = expand(cfg.getString(IF)); - String unlessClause = expand(cfg.getString(UNLESS)); - - if ((ifClause != null && ifClause.length() == 0) || - (unlessClause != null && unlessClause.length() > 0) || - (parentGroup != null && inactiveSteps.containsValue(parentGroup))) { - inactiveSteps.put(step.name(), step); - return false; - } - - if (parentGroup != null) { - parentGroup.addChild(step); - } - - steps.put(step.name(), step); - processRequirements(step, expand(cfg.getString(REQUIRES)), namespace); - previous = step.name(); - return true; - } - - /** - * Processes a parallel clone group directive. - * - * @param cfg hierarchical definition - * @param namespace optional namespace - * @param parentGroup optional parent group - */ - private void processParallelGroup(HierarchicalConfiguration cfg, - String namespace, Group parentGroup) { - String var = cfg.getString(VAR); - print("parallel var=%s", var); - - int i = 1; - while (condition(var, i).length() > 0) { - clonables.add(0, i); - compile(cfg, namespace, parentGroup); - clonables.remove(0); - i++; - } - } - - /** - * Processes a sequential clone group directive. - * - * @param cfg hierarchical definition - * @param namespace optional namespace - * @param parentGroup optional parent group - */ - private void processSequentialGroup(HierarchicalConfiguration cfg, - String namespace, Group parentGroup) { - String var = cfg.getString(VAR); - String starts = cfg.getString(STARTS); - String ends = cfg.getString(ENDS); - print("sequential var=%s", var); - - int i = 1; - while (condition(var, i).length() > 0) { - clonables.add(0, i); - compile(cfg, namespace, parentGroup); - if (i > 1) { - processSequentialRequirements(starts, ends, namespace); - } - clonables.remove(0); - i++; - } - } - - /** - * Hooks starts of this sequence tier to the previous tier. - * - * @param starts comma-separated list of start steps - * @param ends comma-separated list of end steps - * @param namespace optional namespace - */ - private void processSequentialRequirements(String starts, String ends, - String namespace) { - for (String s : split(starts)) { - String start = expand(prefix(s, namespace)); - String reqs = requirements.get(s); - for (String n : split(ends)) { - boolean isSoft = n.startsWith("~"); - String name = n.replaceFirst("^~", ""); - name = (isSoft ? "~" : "") + expand(prefix(name, namespace)); - reqs = reqs == null ? name : (reqs + "," + name); - } - requirements.put(start, reqs); - } - } - - /** - * Returns the elaborated repetition construct conditional. - * - * @param var repetition var property - * @param i index to elaborate - * @return elaborated string - */ - private String condition(String var, Integer i) { - return expand(var.replaceFirst("#", i.toString())).trim(); - } - - /** - * Processes a dependency directive. - * - * @param cfg hierarchical definition - * @param namespace optional namespace - */ - private void processDependency(HierarchicalConfiguration cfg, String namespace) { - String name = expand(prefix(cfg.getString(NAME), namespace)); - String requires = expand(cfg.getString(REQUIRES)); - - print("dependency name=%s requires=%s", name, requires); - Step step = getStep(name, namespace); - if (!inactiveSteps.containsValue(step)) { - processRequirements(step, requires, namespace); - } - } - - /** - * Processes the specified requiremenst string and adds dependency for - * each requirement of the given step. - * - * @param src source step - * @param requires comma-separated list of required steps - * @param namespace optional namespace - */ - private void processRequirements(Step src, String requires, String namespace) { - String reqs = requirements.get(src.name()); - for (String n : split(requires)) { - boolean isSoft = n.startsWith("~"); - String name = n.replaceFirst("^~", ""); - name = previous != null && name.equals("^") ? previous : name; - name = (isSoft ? "~" : "") + expand(prefix(name, namespace)); - reqs = reqs == null ? name : (reqs + "," + name); - } - requirements.put(src.name(), reqs); - } - - /** - * Retrieves the step or group with the specified name. - * - * @param name step or group name - * @param namespace optional namespace - * @return step or group; null if none found in active or inactive steps - */ - private Step getStep(String name, String namespace) { - String dName = prefix(name, namespace); - Step step = steps.get(dName); - step = step != null ? step : inactiveSteps.get(dName); - checkArgument(step != null, "Unknown step %s", dName); - return step; - } - - /** - * Prefixes the specified name with the given namespace. - * - * @param name name of a step or a group - * @param namespace optional namespace - * @return composite name - */ - private String prefix(String name, String namespace) { - return isNullOrEmpty(namespace) ? name : namespace + "." + name; - } - - /** - * Expands any environment variables in the specified string. These are - * specified as ${property} tokens. - * - * @param string string to be processed - * @param keepTokens true if the original unresolved tokens should be kept - * @return original string with expanded substitutions - */ - private String expand(String string, boolean... keepTokens) { - if (string == null) { - return null; - } - - String pString = string; - StringBuilder sb = new StringBuilder(); - int start, end, last = 0; - while ((start = pString.indexOf(PROP_START, last)) >= 0) { - end = pString.indexOf(PROP_END, start + PROP_START.length()); - checkArgument(end > start, "Malformed property in %s", pString); - sb.append(pString.substring(last, start)); - String prop = pString.substring(start + PROP_START.length(), end); - String value; - if (prop.equals(HASH)) { - value = Integer.toString(clonables.get(0)); - } else if (prop.equals(HASH_PREV)) { - value = Integer.toString(clonables.get(0) - 1); - } else if (prop.endsWith(HASH)) { - pString = pString.replaceFirst("#}", clonables.get(0) + "}"); - last = start; - continue; - } else { - // Try system property first, then fall back to env. variable. - value = System.getProperty(prop); - if (value == null) { - value = System.getenv(prop); - } - } - if (value == null && keepTokens.length == 1 && keepTokens[0]) { - sb.append("${").append(prop).append("}"); - } else { - sb.append(value != null ? value : ""); - } - last = end + 1; - } - sb.append(pString.substring(last)); - return sb.toString().replace('\n', ' ').replace('\r', ' '); - } - - /** - * Splits the comma-separated string into a list of strings. - * - * @param string string to split - * @return list of strings - */ - private List<String> split(String string) { - ImmutableList.Builder<String> builder = ImmutableList.builder(); - String[] fields = string != null ? string.split(",") : new String[0]; - for (String field : fields) { - builder.add(field.trim()); - } - return builder.build(); - } - - /** - * Scans the process flow graph for cyclic dependencies. - */ - private void scanForCycles() { - DepthFirstSearch<Step, Dependency> dfs = new DepthFirstSearch<>(); - // Use a brute-force method of searching paths from all vertices. - processFlow().getVertexes().forEach(s -> { - DepthFirstSearch<Step, Dependency>.SpanningTreeResult r = - dfs.search(processFlow, s, null, null, ALL_PATHS); - r.edges().forEach((e, et) -> checkArgument(et != BACK_EDGE, - "Process flow has a cycle involving dependency from %s to %s", - e.src().name, e.dst().name)); - }); - } - - - /** - * Prints formatted output. - * - * @param format printf format string - * @param args arguments to be printed - */ - private void print(String format, Object... args) { - if (debugOn) { - System.err.println(pfx + String.format(format, args)); - } - } - -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Coordinator.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Coordinator.java deleted file mode 100644 index 228e7834..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Coordinator.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import java.io.File; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.concurrent.Executors.newFixedThreadPool; -import static org.onlab.stc.Compiler.PROP_END; -import static org.onlab.stc.Compiler.PROP_START; -import static org.onlab.stc.Coordinator.Directive.*; -import static org.onlab.stc.Coordinator.Status.*; - -/** - * Coordinates execution of a scenario process flow. - */ -public class Coordinator { - - private static final int MAX_THREADS = 64; - - private final ExecutorService executor = newFixedThreadPool(MAX_THREADS); - - private final ProcessFlow processFlow; - - private final StepProcessListener delegate; - private final CountDownLatch latch; - private final ScenarioStore store; - - private static final Pattern PROP_ERE = Pattern.compile("^@stc ([a-zA-Z0-9_.]+)=(.*$)"); - private final Map<String, String> properties = Maps.newConcurrentMap(); - - private final Set<StepProcessListener> listeners = Sets.newConcurrentHashSet(); - private File logDir; - - /** - * Represents action to be taken on a test step. - */ - public enum Directive { - NOOP, RUN, SKIP - } - - /** - * Represents processor state. - */ - public enum Status { - WAITING, IN_PROGRESS, SUCCEEDED, FAILED, SKIPPED - } - - /** - * Creates a process flow coordinator. - * - * @param scenario test scenario to coordinate - * @param processFlow process flow to coordinate - * @param logDir scenario log directory - */ - public Coordinator(Scenario scenario, ProcessFlow processFlow, File logDir) { - this.processFlow = processFlow; - this.logDir = logDir; - this.store = new ScenarioStore(processFlow, logDir, scenario.name()); - this.delegate = new Delegate(); - this.latch = new CountDownLatch(1); - } - - /** - * Resets any previously accrued status and events. - */ - public void reset() { - store.reset(); - } - - /** - * Resets all previously accrued status and events for steps that lie - * in the range between the steps or groups whose names match the specified - * patterns. - * - * @param runFromPatterns list of starting step patterns - * @param runToPatterns list of ending step patterns - */ - public void reset(List<String> runFromPatterns, List<String> runToPatterns) { - List<Step> fromSteps = matchSteps(runFromPatterns); - List<Step> toSteps = matchSteps(runToPatterns); - - // FIXME: implement this - } - - /** - * Returns number of milliseconds it took to execute. - * - * @return number of millis elapsed during the run - */ - public long duration() { - return store.endTime() - store.startTime(); - } - - /** - * Returns a list of steps that match the specified list of patterns. - * - * @param runToPatterns list of patterns - * @return list of steps with matching names - */ - private List<Step> matchSteps(List<String> runToPatterns) { - ImmutableList.Builder<Step> builder = ImmutableList.builder(); - store.getSteps().forEach(step -> { - runToPatterns.forEach(p -> { - if (step.name().matches(p)) { - builder.add(step); - } - }); - }); - return builder.build(); - } - - /** - * Starts execution of the process flow graph. - */ - public void start() { - executeRoots(null); - } - - /** - * Waits for completion of the entire process flow. - * - * @return exit code to use - * @throws InterruptedException if interrupted while waiting for completion - */ - public int waitFor() throws InterruptedException { - while (!store.isComplete()) { - latch.await(1, TimeUnit.SECONDS); - } - return store.hasFailures() ? 1 : 0; - } - - /** - * Returns set of all test steps. - * - * @return set of steps - */ - public Set<Step> getSteps() { - return store.getSteps(); - } - - /** - * Returns a chronological list of step or group records. - * - * @return list of events - */ - List<StepEvent> getRecords() { - return store.getEvents(); - } - - /** - * Returns the status record of the specified test step. - * - * @param step test step or group - * @return step status record - */ - public Status getStatus(Step step) { - return store.getStatus(step); - } - - /** - * Adds the specified listener. - * - * @param listener step process listener - */ - public void addListener(StepProcessListener listener) { - listeners.add(checkNotNull(listener, "Listener cannot be null")); - } - - /** - * Removes the specified listener. - * - * @param listener step process listener - */ - public void removeListener(StepProcessListener listener) { - listeners.remove(checkNotNull(listener, "Listener cannot be null")); - } - - /** - * Executes the set of roots in the scope of the specified group or globally - * if no group is given. - * - * @param group optional group - */ - private void executeRoots(Group group) { - // FIXME: add ability to skip past completed steps - Set<Step> steps = - group != null ? group.children() : processFlow.getVertexes(); - steps.forEach(step -> { - if (processFlow.getEdgesFrom(step).isEmpty() && step.group() == group) { - execute(step); - } - }); - } - - /** - * Executes the specified step. - * - * @param step step to execute - */ - private synchronized void execute(Step step) { - Directive directive = nextAction(step); - if (directive == RUN) { - store.markStarted(step); - if (step instanceof Group) { - Group group = (Group) step; - delegate.onStart(group, null); - executeRoots(group); - } else { - executor.execute(new StepProcessor(step, logDir, delegate, - substitute(step.command()))); - } - } else if (directive == SKIP) { - skipStep(step); - } - } - - /** - * Recursively skips the specified step or group and any steps/groups within. - * - * @param step step or group - */ - private void skipStep(Step step) { - if (step instanceof Group) { - Group group = (Group) step; - store.markComplete(step, SKIPPED); - group.children().forEach(this::skipStep); - } - delegate.onCompletion(step, SKIPPED); - - } - - /** - * Determines the state of the specified step. - * - * @param step test step - * @return state of the step process - */ - private Directive nextAction(Step step) { - Status status = store.getStatus(step); - if (status != WAITING) { - return NOOP; - } - - for (Dependency dependency : processFlow.getEdgesFrom(step)) { - Status depStatus = store.getStatus(dependency.dst()); - if (depStatus == WAITING || depStatus == IN_PROGRESS) { - return NOOP; - } else if (((depStatus == FAILED || depStatus == SKIPPED) && !dependency.isSoft()) || - (step.group() != null && store.getStatus(step.group()) == SKIPPED)) { - return SKIP; - } - } - return RUN; - } - - /** - * Executes the successors to the specified step. - * - * @param step step whose successors are to be executed - */ - private void executeSucessors(Step step) { - processFlow.getEdgesTo(step).forEach(dependency -> execute(dependency.src())); - completeParentIfNeeded(step.group()); - } - - /** - * Checks whether the specified parent group, if any, should be marked - * as complete. - * - * @param group parent group that should be checked - */ - private synchronized void completeParentIfNeeded(Group group) { - if (group != null && getStatus(group) == IN_PROGRESS) { - boolean done = true; - boolean failed = false; - for (Step child : group.children()) { - Status status = store.getStatus(child); - done = done && (status == SUCCEEDED || status == FAILED || status == SKIPPED); - failed = failed || status == FAILED; - } - if (done) { - delegate.onCompletion(group, failed ? FAILED : SUCCEEDED); - } - } - } - - /** - * Expands the var references with values from the properties map. - * - * @param string string to perform substitutions on - */ - private String substitute(String string) { - StringBuilder sb = new StringBuilder(); - int start, end, last = 0; - while ((start = string.indexOf(PROP_START, last)) >= 0) { - end = string.indexOf(PROP_END, start + PROP_START.length()); - checkArgument(end > start, "Malformed property in %s", string); - sb.append(string.substring(last, start)); - String prop = string.substring(start + PROP_START.length(), end); - String value = properties.get(prop); - sb.append(value != null ? value : ""); - last = end + 1; - } - sb.append(string.substring(last)); - return sb.toString().replace('\n', ' ').replace('\r', ' '); - } - - /** - * Scrapes the line of output for any variables to be captured and posted - * in the properties for later use. - * - * @param line line of output to scrape for property exports - */ - private void scrapeForVariables(String line) { - Matcher matcher = PROP_ERE.matcher(line); - if (matcher.matches()) { - String prop = matcher.group(1); - String value = matcher.group(2); - properties.put(prop, value); - } - } - - - /** - * Prints formatted output. - * - * @param format printf format string - * @param args arguments to be printed - */ - public static void print(String format, Object... args) { - System.out.println(String.format(format, args)); - } - - /** - * Internal delegate to monitor the process execution. - */ - private class Delegate implements StepProcessListener { - @Override - public void onStart(Step step, String command) { - listeners.forEach(listener -> listener.onStart(step, command)); - } - - @Override - public void onCompletion(Step step, Status status) { - store.markComplete(step, status); - listeners.forEach(listener -> listener.onCompletion(step, status)); - executeSucessors(step); - if (store.isComplete()) { - latch.countDown(); - } - } - - @Override - public void onOutput(Step step, String line) { - scrapeForVariables(line); - listeners.forEach(listener -> listener.onOutput(step, line)); - } - } - -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Dependency.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Dependency.java deleted file mode 100644 index 9025d2e5..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Dependency.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.base.MoreObjects; -import org.onlab.graph.AbstractEdge; - -import java.util.Objects; - -/** - * Representation of a dependency from one step on completion of another. - */ -public class Dependency extends AbstractEdge<Step> { - - private boolean isSoft; - - /** - * Creates a new edge between the specified source and destination vertexes. - * - * @param src source vertex - * @param dst destination vertex - * @param isSoft indicates whether this is a hard or soft dependency - */ - public Dependency(Step src, Step dst, boolean isSoft) { - super(src, dst); - this.isSoft = isSoft; - } - - /** - * Indicates whether this is a soft or hard dependency, i.e. one that - * requires successful completion of the dependency or just any completion. - * - * @return true if dependency is a soft one - */ - public boolean isSoft() { - return isSoft; - } - - @Override - public int hashCode() { - return 31 * super.hashCode() + Objects.hash(isSoft); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof Dependency) { - final Dependency other = (Dependency) obj; - return super.equals(other) && Objects.equals(this.isSoft, other.isSoft); - } - return false; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("name", src().name()) - .add("requires", dst().name()) - .add("isSoft", isSoft) - .toString(); - } -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Group.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Group.java deleted file mode 100644 index 0281c364..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Group.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; - -import java.util.Set; - -/** - * Represenation of a related group of steps. - */ -public class Group extends Step { - - private final Set<Step> children = Sets.newHashSet(); - - /** - * Creates a new test step. - * - * @param name group name - * @param command default command - * @param env default path to file to be sourced into the environment - * @param cwd default path to current working directory for the step - * @param group optional group to which this step belongs - */ - public Group(String name, String command, String env, String cwd, Group group) { - super(name, command, env, cwd, group); - } - - /** - * Returns the set of child steps and groups contained within this group. - * - * @return set of children - */ - public Set<Step> children() { - return ImmutableSet.copyOf(children); - } - - /** - * Adds the specified step or group as a child of this group. - * - * @param child child step or group to add - */ - public void addChild(Step child) { - children.add(child); - } -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java deleted file mode 100644 index ca04a7c2..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Main.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.collect.ImmutableList; -import com.google.common.io.Files; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletHandler; -import org.eclipse.jetty.util.log.Logger; -import org.onlab.stc.Coordinator.Status; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static java.lang.System.currentTimeMillis; -import static org.onlab.stc.Coordinator.Status.*; -import static org.onlab.stc.Coordinator.print; - -/** - * Main program for executing system test coordinator. - */ -public final class Main { - - private static final String NONE = "\u001B[0m"; - private static final String GRAY = "\u001B[30;1m"; - private static final String RED = "\u001B[31;1m"; - private static final String GREEN = "\u001B[32;1m"; - private static final String BLUE = "\u001B[36m"; - - private static final String SUCCESS_SUMMARY = - "%s %sPassed! %d steps succeeded%s"; - private static final String MIXED_SUMMARY = - "%s%d steps succeeded; %s%d steps failed; %s%d steps skipped%s"; - private static final String FAILURE_SUMMARY = "%s %sFailed! " + MIXED_SUMMARY; - private static final String ABORTED_SUMMARY = "%s %sAborted! " + MIXED_SUMMARY; - - private boolean isReported = false; - - private enum Command { - LIST, RUN, RUN_RANGE, HELP - } - - private final String scenarioFile; - - private Command command = Command.HELP; - private String runFromPatterns = ""; - private String runToPatterns = ""; - - private Coordinator coordinator; - private Compiler compiler; - private Monitor monitor; - private Listener delegate = new Listener(); - - private static boolean useColor = Objects.equals("true", System.getenv("stcColor")); - private static boolean dumpLogs = Objects.equals("true", System.getenv("stcDumpLogs")); - - // usage: stc [<scenario-file>] [run] - // usage: stc [<scenario-file>] run [from <from-patterns>] [to <to-patterns>]] - // usage: stc [<scenario-file>] list - - // Public construction forbidden - private Main(String[] args) { - this.scenarioFile = args[0]; - - if (args.length <= 1 || args.length == 2 && args[1].equals("run")) { - command = Command.RUN; - } else if (args.length == 2 && args[1].equals("list")) { - command = Command.LIST; - } else if (args.length >= 4 && args[1].equals("run")) { - int i = 2; - if (args[i].equals("from")) { - command = Command.RUN_RANGE; - runFromPatterns = args[i + 1]; - i += 2; - } - - if (args.length >= i + 2 && args[i].equals("to")) { - command = Command.RUN_RANGE; - runToPatterns = args[i + 1]; - } - } - } - - /** - * Main entry point for coordinating test scenario execution. - * - * @param args command-line arguments - */ - public static void main(String[] args) { - Main main = new Main(args); - main.run(); - } - - // Runs the scenario processing - private void run() { - try { - // Load scenario - Scenario scenario = Scenario.loadScenario(new FileInputStream(scenarioFile)); - - // Elaborate scenario - compiler = new Compiler(scenario); - compiler.compile(); - - // Setup the process flow coordinator - coordinator = new Coordinator(scenario, compiler.processFlow(), - compiler.logDir()); - coordinator.addListener(delegate); - - // Prepare the GUI monitor - monitor = new Monitor(coordinator, compiler); - startMonitorServer(monitor); - - // Execute process flow - processCommand(); - - } catch (FileNotFoundException e) { - print("Unable to find scenario file %s", scenarioFile); - } - } - - // Initiates a web-server for the monitor GUI. - private static void startMonitorServer(Monitor monitor) { - org.eclipse.jetty.util.log.Log.setLog(new NullLogger()); - Server server = new Server(9999); - ServletHandler handler = new ServletHandler(); - server.setHandler(handler); - MonitorWebSocketServlet.setMonitor(monitor); - handler.addServletWithMapping(MonitorWebSocketServlet.class, "/*"); - try { - server.start(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - // Processes the appropriate command - private void processCommand() { - switch (command) { - case RUN: - processRun(); - break; - case LIST: - processList(); - break; - case RUN_RANGE: - processRunRange(); - break; - default: - print("Unsupported command %s", command); - } - } - - // Processes the scenario 'run' command. - private void processRun() { - coordinator.reset(); - runCoordinator(); - } - - // Processes the scenario 'run' command for range of steps. - private void processRunRange() { - coordinator.reset(list(runFromPatterns), list(runToPatterns)); - runCoordinator(); - } - - // Processes the scenario 'list' command. - private void processList() { - coordinator.getRecords() - .forEach(event -> logStatus(event.time(), event.name(), event.status(), event.command())); - printSummary(0, false); - System.exit(0); - } - - // Runs the coordinator and waits for it to finish. - private void runCoordinator() { - try { - Runtime.getRuntime().addShutdownHook(new ShutdownHook()); - coordinator.start(); - int exitCode = coordinator.waitFor(); - pause(100); // allow stdout to flush - printSummary(exitCode, false); - System.exit(exitCode); - } catch (InterruptedException e) { - print("Unable to execute scenario %s", scenarioFile); - } - } - - private synchronized void printSummary(int exitCode, boolean isAborted) { - if (!isReported) { - isReported = true; - Set<Step> steps = coordinator.getSteps(); - String duration = formatDuration((int) (coordinator.duration() / 1_000)); - int count = steps.size(); - if (exitCode == 0) { - print(SUCCESS_SUMMARY, duration, color(SUCCEEDED), count, color(null)); - } else { - long success = steps.stream().filter(s -> coordinator.getStatus(s) == SUCCEEDED).count(); - long failed = steps.stream().filter(s -> coordinator.getStatus(s) == FAILED).count(); - long skipped = steps.stream().filter(s -> coordinator.getStatus(s) == SKIPPED).count(); - print(isAborted ? ABORTED_SUMMARY : FAILURE_SUMMARY, duration, - color(FAILED), color(SUCCEEDED), success, - color(FAILED), failed, color(SKIPPED), skipped, color(null)); - } - } - } - - /** - * Internal delegate to monitor the process execution. - */ - private class Listener implements StepProcessListener { - @Override - public void onStart(Step step, String command) { - logStatus(currentTimeMillis(), step.name(), IN_PROGRESS, command); - } - - @Override - public void onCompletion(Step step, Status status) { - logStatus(currentTimeMillis(), step.name(), status, null); - if (dumpLogs && !(step instanceof Group) && status == FAILED) { - dumpLogs(step); - } - } - - @Override - public void onOutput(Step step, String line) { - } - } - - // Logs the step status. - private static void logStatus(long time, String name, Status status, String cmd) { - if (cmd != null) { - print("%s %s%s %s%s -- %s", time(time), color(status), name, action(status), color(null), cmd); - } else { - print("%s %s%s %s%s", time(time), color(status), name, action(status), color(null)); - } - } - - // Dumps the step logs to standard output. - private void dumpLogs(Step step) { - File logFile = new File(compiler.logDir(), step.name() + ".log"); - try { - print(">>>>>"); - Files.copy(logFile, System.out); - print("<<<<<"); - } catch (IOException e) { - print("Unable to dump log file %s", logFile.getName()); - } - } - - // Produces a description of event using the specified step status. - private static String action(Status status) { - return status == IN_PROGRESS ? "started" : - (status == SUCCEEDED ? "completed" : - (status == FAILED ? "failed" : - (status == SKIPPED ? "skipped" : "waiting"))); - } - - // Produces an ANSI escape code for color using the specified step status. - private static String color(Status status) { - if (!useColor) { - return ""; - } - return status == null ? NONE : - (status == IN_PROGRESS ? BLUE : - (status == SUCCEEDED ? GREEN : - (status == FAILED ? RED : GRAY))); - } - - // Produces a list from the specified comma-separated string. - private static List<String> list(String patterns) { - return ImmutableList.copyOf(patterns.split(",")); - } - - // Produces a formatted time stamp. - private static String time(long time) { - return new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date(time)); - } - - // Pauses for the specified number of millis. - private static void pause(int ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - print("Interrupted!"); - } - } - - // Formats time duration - private static String formatDuration(int totalSeconds) { - int seconds = totalSeconds % 60; - int totalMinutes = totalSeconds / 60; - int minutes = totalMinutes % 60; - int hours = totalMinutes / 60; - return hours > 0 ? - String.format("%d:%02d:%02d", hours, minutes, seconds) : - String.format("%d:%02d", minutes, seconds); - } - - // Shutdown hook to report status even when aborted. - private class ShutdownHook extends Thread { - @Override - public void run() { - printSummary(1, true); - } - } - - // Logger to quiet Jetty down - private static class NullLogger implements Logger { - @Override - public String getName() { - return "quiet"; - } - - @Override - public void warn(String msg, Object... args) { - } - - @Override - public void warn(Throwable thrown) { - } - - @Override - public void warn(String msg, Throwable thrown) { - } - - @Override - public void info(String msg, Object... args) { - } - - @Override - public void info(Throwable thrown) { - } - - @Override - public void info(String msg, Throwable thrown) { - } - - @Override - public boolean isDebugEnabled() { - return false; - } - - @Override - public void setDebugEnabled(boolean enabled) { - } - - @Override - public void debug(String msg, Object... args) { - } - - @Override - public void debug(Throwable thrown) { - } - - @Override - public void debug(String msg, Throwable thrown) { - } - - @Override - public Logger getLogger(String name) { - return this; - } - - @Override - public void ignore(Throwable ignored) { - } - } -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Monitor.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Monitor.java deleted file mode 100644 index 4e6f63fa..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Monitor.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.collect.Maps; -import org.onlab.stc.MonitorLayout.Box; - -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Map; - -import static org.onlab.stc.Coordinator.Status.IN_PROGRESS; - -/** - * Scenario test monitor. - */ -public class Monitor implements StepProcessListener { - - private final ObjectMapper mapper = new ObjectMapper(); - - private final Coordinator coordinator; - private final Compiler compiler; - private final MonitorLayout layout; - - private MonitorDelegate delegate; - - private Map<Step, Box> boxes = Maps.newHashMap(); - - /** - * Creates a new shared process flow monitor. - * - * @param coordinator process flow coordinator - * @param compiler scenario compiler - */ - Monitor(Coordinator coordinator, Compiler compiler) { - this.coordinator = coordinator; - this.compiler = compiler; - this.layout = new MonitorLayout(compiler); - coordinator.addListener(this); - } - - /** - * Sets the process monitor delegate. - * - * @param delegate process monitor delegate - */ - void setDelegate(MonitorDelegate delegate) { - this.delegate = delegate; - } - - /** - * Notifies the process monitor delegate with the specified event. - * - * @param event JSON event data - */ - public void notify(ObjectNode event) { - if (delegate != null) { - delegate.notify(event); - } - } - - /** - * Returns the scenario process flow as JSON data. - * - * @return scenario process flow data - */ - ObjectNode scenarioData() { - ObjectNode root = mapper.createObjectNode(); - ArrayNode steps = mapper.createArrayNode(); - ArrayNode requirements = mapper.createArrayNode(); - - ProcessFlow pf = compiler.processFlow(); - pf.getVertexes().forEach(step -> add(step, steps)); - pf.getEdges().forEach(requirement -> add(requirement, requirements)); - - root.set("steps", steps); - root.set("requirements", requirements); - - try (FileWriter fw = new FileWriter("/tmp/data.json"); - PrintWriter pw = new PrintWriter(fw)) { - pw.println(root.toString()); - } catch (IOException e) { - e.printStackTrace(); - } - return root; - } - - - private void add(Step step, ArrayNode steps) { - Box box = layout.get(step); - ObjectNode sn = mapper.createObjectNode() - .put("name", step.name()) - .put("isGroup", step instanceof Group) - .put("status", status(coordinator.getStatus(step))) - .put("tier", box.tier()) - .put("depth", box.depth()); - if (step.group() != null) { - sn.put("group", step.group().name()); - } - steps.add(sn); - } - - private String status(Coordinator.Status status) { - return status.toString().toLowerCase(); - } - - private void add(Dependency requirement, ArrayNode requirements) { - ObjectNode rn = mapper.createObjectNode(); - rn.put("src", requirement.src().name()) - .put("dst", requirement.dst().name()) - .put("isSoft", requirement.isSoft()); - requirements.add(rn); - } - - @Override - public void onStart(Step step, String command) { - notify(event(step, status(IN_PROGRESS))); - } - - @Override - public void onCompletion(Step step, Coordinator.Status status) { - notify(event(step, status(status))); - } - - @Override - public void onOutput(Step step, String line) { - - } - - private ObjectNode event(Step step, String status) { - ObjectNode event = mapper.createObjectNode() - .put("name", step.name()) - .put("status", status); - return event; - } - -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorDelegate.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorDelegate.java deleted file mode 100644 index d11542a7..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorDelegate.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** - * Delegate to which monitor can send notifications. - */ -public interface MonitorDelegate { - - /** - * Issues JSON event to be sent to any connected monitor clients. - * - * @param event JSON event data - */ - void notify(ObjectNode event); -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorLayout.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorLayout.java deleted file mode 100644 index 1c0e7313..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorLayout.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * Computes scenario process flow layout for the Monitor GUI. - */ -public class MonitorLayout { - - public static final int WIDTH = 210; - public static final int HEIGHT = 30; - public static final int W_GAP = 40; - public static final int H_GAP = 50; - public static final int SLOT_WIDTH = WIDTH + H_GAP; - - private final Compiler compiler; - private final ProcessFlow flow; - - private Map<Step, Box> boxes = Maps.newHashMap(); - - /** - * Creates a new shared process flow monitor. - * - * @param compiler scenario compiler - */ - MonitorLayout(Compiler compiler) { - this.compiler = compiler; - this.flow = compiler.processFlow(); - - // Extract the flow and create initial bounding boxes. - boxes.put(null, new Box(null, 0)); - flow.getVertexes().forEach(this::createBox); - - computeLayout(null, 0, 1); - } - - // Computes the graph layout giving preference to group associations. - private void computeLayout(Group group, int absoluteTier, int tier) { - Box box = boxes.get(group); - - // Find all children of the group, or items with no group if at top. - Set<Step> children = group != null ? group.children() : - flow.getVertexes().stream().filter(s -> s.group() == null) - .collect(Collectors.toSet()); - - children.forEach(s -> visit(s, absoluteTier, 1, group)); - - // Figure out what the group root vertexes are. - Set<Step> roots = findRoots(group); - - // Compute the boxes for each of the roots. - roots.forEach(s -> updateBox(s, absoluteTier + 1, 1, group)); - - // Update the tier and depth of the group bounding box. - computeTiersAndDepth(group, box, absoluteTier, tier, children); - - // Compute the minimum breadth of this group's bounding box. - computeBreadth(group, box, children); - - // Compute child placements - computeChildPlacements(group, box, children); - } - - // Updates the box for the specified step, given the tier number, which - // is relative to the parent. - private Box updateBox(Step step, int absoluteTier, int tier, Group group) { - Box box = boxes.get(step); - if (step instanceof Group) { - computeLayout((Group) step, absoluteTier, tier); - } else { - box.setTierAndDepth(absoluteTier, tier, 1, group); - } - - // Follow the steps downstream of this one. - follow(step, absoluteTier + box.depth(), box.tier() + box.depth()); - return box; - } - - // Backwards follows edges leading towards the specified step to visit - // the source vertex and compute layout of those vertices that had - // sufficient number of visits to compute their tier. - private void follow(Step step, int absoluteTier, int tier) { - Group from = step.group(); - flow.getEdgesTo(step).stream() - .filter(d -> visit(d.src(), absoluteTier, tier, from)) - .forEach(d -> updateBox(d.src(), absoluteTier, tier, from)); - } - - // Visits each step, records maximum tier and returns true if this - // was the last expected visit. - private boolean visit(Step step, int absoluteTier, int tier, Group from) { - Box box = boxes.get(step); - return box.visitAndLatchMaxTier(absoluteTier, tier, from); - } - - // Computes the absolute and relative tiers and the depth of the group - // bounding box. - private void computeTiersAndDepth(Group group, Box box, - int absoluteTier, int tier, Set<Step> children) { - int depth = children.stream().mapToInt(this::bottomMostTier).max().getAsInt(); - box.setTierAndDepth(absoluteTier, tier, depth, group); - } - - // Returns the bottom-most tier this step occupies relative to its parent. - private int bottomMostTier(Step step) { - Box box = boxes.get(step); - return box.tier() + box.depth(); - } - - // Computes breadth of the specified group. - private void computeBreadth(Group group, Box box, Set<Step> children) { - if (box.breadth() == 0) { - // Scan through all tiers and determine the maximum breadth of each. - IntStream.range(1, box.depth) - .forEach(t -> computeTierBreadth(t, box, children)); - box.latchBreadth(children.stream() - .mapToInt(s -> boxes.get(s).breadth()) - .max().getAsInt()); - } - } - - // Computes tier width. - private void computeTierBreadth(int t, Box box, Set<Step> children) { - box.latchBreadth(children.stream().map(boxes::get) - .filter(b -> isSpanningTier(b, t)) - .mapToInt(Box::breadth).sum()); - } - - // Computes the actual child box placements relative to the parent using - // the previously established tier, depth and breadth attributes. - private void computeChildPlacements(Group group, Box box, - Set<Step> children) { - // Order the root-nodes in alphanumeric order first. - List<Box> tierBoxes = Lists.newArrayList(boxesOnTier(1, children)); - tierBoxes.sort((a, b) -> a.step().name().compareTo(b.step().name())); - - // Place the boxes centered on the parent box; left to right. - int tierBreadth = tierBoxes.stream().mapToInt(Box::breadth).sum(); - int slot = 1; - for (Box b : tierBoxes) { - b.updateCenter(1, slot(slot, tierBreadth)); - slot += b.breadth(); - } - } - - // Returns the horizontal offset off the parent center. - private int slot(int slot, int tierBreadth) { - boolean even = tierBreadth % 2 == 0; - int multiplier = -tierBreadth / 2 + slot - 1; - return even ? multiplier * SLOT_WIDTH + SLOT_WIDTH / 2 : multiplier * SLOT_WIDTH; - } - - // Returns a list of all child step boxes that start on the specified tier. - private List<Box> boxesOnTier(int tier, Set<Step> children) { - return boxes.values().stream() - .filter(b -> b.tier() == tier && children.contains(b.step())) - .collect(Collectors.toList()); - } - - // Determines whether the specified box spans, or occupies a tier. - private boolean isSpanningTier(Box b, int tier) { - return (b.depth() == 1 && b.tier() == tier) || - (b.tier() <= tier && tier < b.tier() + b.depth()); - } - - - // Determines roots of the specified group or of the entire graph. - private Set<Step> findRoots(Group group) { - Set<Step> steps = group != null ? group.children() : flow.getVertexes(); - return steps.stream().filter(s -> isRoot(s, group)).collect(Collectors.toSet()); - } - - private boolean isRoot(Step step, Group group) { - if (step.group() != group) { - return false; - } - - Set<Dependency> requirements = flow.getEdgesFrom(step); - return requirements.stream().filter(r -> r.dst().group() == group) - .collect(Collectors.toSet()).isEmpty(); - } - - /** - * Returns the bounding box for the specified step. If null is given, it - * returns the overall bounding box. - * - * @param step step or group; null for the overall bounding box - * @return bounding box - */ - public Box get(Step step) { - return boxes.get(step); - } - - /** - * Returns the bounding box for the specified step name. If null is given, - * it returns the overall bounding box. - * - * @param name name of step or group; null for the overall bounding box - * @return bounding box - */ - public Box get(String name) { - return get(name == null ? null : compiler.getStep(name)); - } - - // Creates a bounding box for the specified step or group. - private void createBox(Step step) { - boxes.put(step, new Box(step, flow.getEdgesFrom(step).size())); - } - - /** - * Bounding box data for a step or group. - */ - final class Box { - - private Step step; - private int remainingRequirements; - - private int absoluteTier = 0; - private int tier; - private int depth = 1; - private int breadth; - private int center, top; - - private Box(Step step, int remainingRequirements) { - this.step = step; - this.remainingRequirements = remainingRequirements + 1; - breadth = step == null || step instanceof Group ? 0 : 1; - } - - private void latchTiers(int absoluteTier, int tier, Group from) { - this.absoluteTier = Math.max(this.absoluteTier, absoluteTier); - if (step == null || step.group() == from) { - this.tier = Math.max(this.tier, tier); - } - } - - public void latchBreadth(int breadth) { - this.breadth = Math.max(this.breadth, breadth); - } - - void setTierAndDepth(int absoluteTier, int tier, int depth, Group from) { - latchTiers(absoluteTier, tier, from); - this.depth = depth; - } - - boolean visitAndLatchMaxTier(int absoluteTier, int tier, Group from) { - latchTiers(absoluteTier, tier, from); - --remainingRequirements; - return remainingRequirements == 0; - } - - Step step() { - return step; - } - - public int absoluteTier() { - return absoluteTier; - } - - int tier() { - return tier; - } - - int depth() { - return depth; - } - - int breadth() { - return breadth; - } - - int top() { - return top; - } - - int center() { - return center; - } - - public void updateCenter(int top, int center) { - this.top = top; - this.center = center; - } - } -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocket.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocket.java deleted file mode 100644 index cd146070..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocket.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.eclipse.jetty.websocket.WebSocket; - -import java.io.IOException; - -import static org.onlab.stc.Coordinator.print; - -/** - * Web socket capable of interacting with the STC monitor GUI. - */ -public class MonitorWebSocket implements WebSocket.OnTextMessage, WebSocket.OnControl { - - private static final long MAX_AGE_MS = 30_000; - - private static final byte PING = 0x9; - private static final byte PONG = 0xA; - private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad}; - - private final Monitor monitor; - - private Connection connection; - private FrameConnection control; - - private final ObjectMapper mapper = new ObjectMapper(); - - private long lastActive = System.currentTimeMillis(); - - /** - * Creates a new monitor client GUI web-socket. - * - * @param monitor shared process flow monitor - */ - MonitorWebSocket(Monitor monitor) { - this.monitor = monitor; - } - - /** - * Issues a close on the connection. - */ - synchronized void close() { - destroyHandlers(); - if (connection.isOpen()) { - connection.close(); - } - } - - /** - * Indicates if this connection is idle. - * - * @return true if idle or closed - */ - synchronized boolean isIdle() { - long quietFor = System.currentTimeMillis() - lastActive; - boolean idle = quietFor > MAX_AGE_MS; - if (idle || (connection != null && !connection.isOpen())) { - return true; - } else if (connection != null) { - try { - control.sendControl(PING, PING_DATA, 0, PING_DATA.length); - } catch (IOException e) { - print("Unable to send ping message due to: %s", e); - } - } - return false; - } - - @Override - public void onOpen(Connection connection) { - this.connection = connection; - this.control = (FrameConnection) connection; - try { - createHandlers(); - sendMessage(message("flow", monitor.scenarioData())); - - } catch (Exception e) { - print("Unable to open monitor connection: %s", e); - this.connection.close(); - this.connection = null; - this.control = null; - } - } - - @Override - public synchronized void onClose(int closeCode, String message) { - destroyHandlers(); - } - - @Override - public boolean onControl(byte controlCode, byte[] data, int offset, int length) { - lastActive = System.currentTimeMillis(); - return true; - } - - @Override - public void onMessage(String data) { - lastActive = System.currentTimeMillis(); - try { - ObjectNode message = (ObjectNode) mapper.reader().readTree(data); - // TODO: - print("Got message: %s", message); - } catch (Exception e) { - print("Unable to parse GUI message %s due to %s", data, e); - } - } - - public synchronized void sendMessage(ObjectNode message) { - try { - if (connection.isOpen()) { - connection.sendMessage(message.toString()); - } - } catch (IOException e) { - print("Unable to send message %s to GUI due to %s", message, e); - } - } - - public ObjectNode message(String type, ObjectNode payload) { - ObjectNode message = mapper.createObjectNode().put("event", type); - message.set("payload", payload); - return message; - } - - // Creates new message handlers. - private synchronized void createHandlers() { - } - - // Destroys message handlers. - private synchronized void destroyHandlers() { - } - -} - diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocketServlet.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocketServlet.java deleted file mode 100644 index a8705003..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/MonitorWebSocketServlet.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.io.ByteStreams; -import com.google.common.net.MediaType; -import org.eclipse.jetty.websocket.WebSocket; -import org.eclipse.jetty.websocket.WebSocketServlet; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; - -/** - * Web socket servlet capable of creating web sockets for the STC monitor. - */ -public class MonitorWebSocketServlet extends WebSocketServlet - implements MonitorDelegate { - - private static final long PING_DELAY_MS = 5000; - private static final String DOT = "."; - - private static Monitor monitor; - private static MonitorWebSocketServlet instance; - - private final Set<MonitorWebSocket> sockets = new HashSet<>(); - private final Timer timer = new Timer(); - private final TimerTask pruner = new Pruner(); - - /** - * Binds the shared process flow monitor. - * - * @param m process monitor reference - */ - public static void setMonitor(Monitor m) { - monitor = m; - } - - /** - * Closes all currently open monitor web-sockets. - */ - public static void closeAll() { - if (instance != null) { - instance.sockets.forEach(MonitorWebSocket::close); - instance.sockets.clear(); - } - } - - @Override - public void init() throws ServletException { - super.init(); - instance = this; - monitor.setDelegate(this); - timer.schedule(pruner, PING_DELAY_MS, PING_DELAY_MS); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String uri = req.getRequestURI(); - uri = uri.length() <= 1 ? "/index.html" : uri; - InputStream resource = getClass().getResourceAsStream(uri); - if (resource == null) { - resp.setStatus(HttpServletResponse.SC_NOT_FOUND); - } else { - byte[] entity = ByteStreams.toByteArray(resource); - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType(contentType(uri).toString()); - resp.setContentLength(entity.length); - resp.getOutputStream().write(entity); - } - } - - private MediaType contentType(String uri) { - int sep = uri.lastIndexOf(DOT); - String ext = sep > 0 ? uri.substring(sep + 1) : null; - return ext == null ? MediaType.APPLICATION_BINARY : - ext.equals("html") ? MediaType.HTML_UTF_8 : - ext.equals("js") ? MediaType.JAVASCRIPT_UTF_8 : - ext.equals("css") ? MediaType.CSS_UTF_8 : - MediaType.APPLICATION_BINARY; - } - - @Override - public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) { - MonitorWebSocket socket = new MonitorWebSocket(monitor); - synchronized (sockets) { - sockets.add(socket); - } - return socket; - } - - @Override - public void notify(ObjectNode event) { - if (instance != null) { - instance.sockets.forEach(ws -> ws.sendMessage(event)); - } - } - - // Task for pruning web-sockets that are idle. - private class Pruner extends TimerTask { - @Override - public void run() { - synchronized (sockets) { - Iterator<MonitorWebSocket> it = sockets.iterator(); - while (it.hasNext()) { - MonitorWebSocket socket = it.next(); - if (socket.isIdle()) { - it.remove(); - socket.close(); - } - } - } - } - } -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ProcessFlow.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ProcessFlow.java deleted file mode 100644 index 4d99b339..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ProcessFlow.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import org.onlab.graph.MutableAdjacencyListsGraph; - -import java.util.Set; - -/** - * Graph representation of a test process flow. - */ -public class ProcessFlow extends MutableAdjacencyListsGraph<Step, Dependency> { - - /** - * Creates a graph comprising of the specified vertexes and edges. - * - * @param vertexes set of graph vertexes - * @param edges set of graph edges - */ - public ProcessFlow(Set<Step> vertexes, Set<Dependency> edges) { - super(vertexes, edges); - } - -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Scenario.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Scenario.java deleted file mode 100644 index fd2cd62d..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Scenario.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.HierarchicalConfiguration; -import org.apache.commons.configuration.XMLConfiguration; - -import java.io.InputStream; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -/** - * Representation of a re-usable test scenario. - */ -public final class Scenario { - - private static final String SCENARIO = "scenario"; - private static final String NAME = "[@name]"; - private static final String DESCRIPTION = "[@description]"; - - private final String name; - private final String description; - private final HierarchicalConfiguration definition; - - // Creates a new scenario from the specified definition. - private Scenario(String name, String description, HierarchicalConfiguration definition) { - this.name = checkNotNull(name, "Name cannot be null"); - this.description = checkNotNull(description, "Description cannot be null"); - this.definition = checkNotNull(definition, "Definition cannot be null"); - } - - /** - * Loads a new scenario from the specified hierarchical configuration. - * - * @param definition scenario definition - * @return loaded scenario - */ - public static Scenario loadScenario(HierarchicalConfiguration definition) { - String name = definition.getString(NAME); - String description = definition.getString(DESCRIPTION, ""); - checkState(name != null, "Scenario name must be specified"); - return new Scenario(name, description, definition); - } - - /** - * Loads a new scenario from the specified input stream. - * - * @param stream scenario definition stream - * @return loaded scenario - */ - public static Scenario loadScenario(InputStream stream) { - XMLConfiguration cfg = new XMLConfiguration(); - cfg.setAttributeSplittingDisabled(true); - cfg.setDelimiterParsingDisabled(true); - cfg.setRootElementName(SCENARIO); - try { - cfg.load(stream); - return loadScenario(cfg); - } catch (ConfigurationException e) { - throw new IllegalArgumentException("Unable to load scenario from the stream", e); - } - } - - /** - * Returns the scenario name. - * - * @return scenario name - */ - public String name() { - return name; - } - - /** - * Returns the scenario description. - * - * @return scenario description - */ - public String description() { - return description; - } - - /** - * Returns the scenario definition. - * - * @return scenario definition - */ - public HierarchicalConfiguration definition() { - return definition; - } - -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java deleted file mode 100644 index 7313462e..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/ScenarioStore.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.PropertiesConfiguration; -import org.onlab.stc.Coordinator.Status; - -import java.io.File; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.onlab.stc.Coordinator.Status.*; -import static org.onlab.stc.Coordinator.print; - -/** - * Maintains state of scenario execution. - */ -class ScenarioStore { - - private final ProcessFlow processFlow; - private final File storeFile; - private final File logDir; - - private final List<StepEvent> events = Lists.newArrayList(); - private final Map<String, Status> statusMap = Maps.newConcurrentMap(); - - private long startTime = Long.MAX_VALUE; - private long endTime = Long.MIN_VALUE; - - /** - * Creates a new scenario store for the specified process flow. - * - * @param processFlow scenario process flow - * @param logDir scenario log directory - * @param name scenario name - */ - ScenarioStore(ProcessFlow processFlow, File logDir, String name) { - this.processFlow = processFlow; - this.logDir = logDir; - this.storeFile = new File(logDir, name + ".stc"); - load(); - } - - /** - * Resets status of all steps to waiting and clears all events. - */ - void reset() { - events.clear(); - statusMap.clear(); - processFlow.getVertexes().forEach(step -> statusMap.put(step.name(), WAITING)); - try { - removeLogs(); - PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile); - cfg.clear(); - cfg.save(); - startTime = Long.MAX_VALUE; - endTime = Long.MIN_VALUE; - } catch (ConfigurationException e) { - print("Unable to store file %s", storeFile); - } - - } - - /** - * Returns set of all test steps. - * - * @return set of steps - */ - Set<Step> getSteps() { - return processFlow.getVertexes(); - } - - /** - * Returns a chronological list of step or group records. - * - * @return list of events - */ - synchronized List<StepEvent> getEvents() { - return ImmutableList.copyOf(events); - } - - /** - * Returns the status record of the specified test step. - * - * @param step test step or group - * @return step status record - */ - Status getStatus(Step step) { - return checkNotNull(statusMap.get(step.name()), "Step %s not found", step.name()); - } - - /** - * Marks the specified test step as being in progress. - * - * @param step test step or group - */ - synchronized void markStarted(Step step) { - add(new StepEvent(step.name(), IN_PROGRESS, step.command())); - save(); - } - - /** - * Marks the specified test step as being complete. - * - * @param step test step or group - * @param status new step status - */ - synchronized void markComplete(Step step, Status status) { - add(new StepEvent(step.name(), status, null)); - save(); - } - - /** - * Returns true if all steps in the store have been marked as completed - * regardless of the completion status. - * - * @return true if all steps completed one way or another - */ - synchronized boolean isComplete() { - return !statusMap.values().stream().anyMatch(s -> s == WAITING || s == IN_PROGRESS); - } - - /** - * Indicates whether there are any failures. - * - * @return true if there are failed steps - */ - boolean hasFailures() { - for (Status status : statusMap.values()) { - if (status == FAILED) { - return true; - } - } - return false; - } - - /** - * Registers a new step record. - * - * @param event step event - */ - private synchronized void add(StepEvent event) { - events.add(event); - statusMap.put(event.name(), event.status()); - startTime = Math.min(startTime, event.time()); - endTime = Math.max(endTime, event.time()); - } - - /** - * Loads the states from disk. - */ - private void load() { - try { - PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile); - cfg.getKeys().forEachRemaining(prop -> add(StepEvent.fromString(cfg.getString(prop)))); - cfg.save(); - } catch (ConfigurationException e) { - print("Unable to load file %s", storeFile); - } - } - - /** - * Saves the states to disk. - */ - private void save() { - try { - PropertiesConfiguration cfg = new PropertiesConfiguration(storeFile); - events.forEach(event -> cfg.setProperty("T" + event.time(), event.toString())); - cfg.save(); - } catch (ConfigurationException e) { - print("Unable to store file %s", storeFile); - } - } - - /** - * Removes all scenario log files. - */ - private void removeLogs() { - File[] logFiles = logDir.listFiles(); - if (logFiles != null && logFiles.length > 0) { - for (File file : logFiles) { - if (!file.delete()) { - print("Unable to delete log file %s", file); - } - } - } - } - - /** - * Returns the scenario run start time. - * - * @return start time in mills since start of epoch - */ - public long startTime() { - return startTime; - } - - /** - * Returns the scenario run end time or current time if the scenario - * is still running. - * - * @return end time (or current time) in mills since start of epoch - */ - public long endTime() { - return endTime > 0 ? endTime : System.currentTimeMillis(); - } -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Step.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Step.java deleted file mode 100644 index e14addb5..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/Step.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.base.MoreObjects; -import org.onlab.graph.Vertex; - -import java.util.Objects; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Representation of a test step. - */ -public class Step implements Vertex { - - protected final String name; - protected final String command; - protected final String env; - protected final String cwd; - protected final Group group; - - /** - * Creates a new test step. - * - * @param name step name - * @param command step command to execute - * @param env path to file to be sourced into the environment - * @param cwd path to current working directory for the step - * @param group optional group to which this step belongs - */ - public Step(String name, String command, String env, String cwd, Group group) { - this.name = checkNotNull(name, "Name cannot be null"); - this.group = group; - - // Set the command, environment and cwd - // If one is not given use the value from the enclosing group - this.command = command != null ? command : group != null && group.command != null ? group.command : null; - this.env = env != null ? env : group != null && group.env != null ? group.env : null; - this.cwd = cwd != null ? cwd : group != null && group.cwd != null ? group.cwd : null; - } - - /** - * Returns the step name. - * - * @return step name - */ - public String name() { - return name; - } - - /** - * Returns the step command string. - * - * @return command string - */ - public String command() { - return command; - } - - /** - * Returns the step environment script path. - * - * @return env script path - */ - public String env() { - return env; - } - - /** - * Returns the step current working directory path. - * - * @return current working dir path - */ - public String cwd() { - return cwd; - } - - /** - * Returns the enclosing group; null if none. - * - * @return enclosing group or null - */ - public Group group() { - return group; - } - - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof Step) { - final Step other = (Step) obj; - return Objects.equals(this.name, other.name); - } - return false; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("name", name) - .add("command", command) - .add("env", env) - .add("cwd", cwd) - .add("group", group) - .toString(); - } -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepEvent.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepEvent.java deleted file mode 100644 index c9b81a24..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepEvent.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import org.onlab.stc.Coordinator.Status; - -import static java.lang.Long.parseLong; -import static org.onlab.stc.Coordinator.Status.valueOf; - -/** - * Represents an event of execution of a scenario step or group. - */ -public class StepEvent { - - private static final String SEP = "~"; - - private final String name; - private final long time; - private final Status status; - private final String command; - - /** - * Creates a new step record. - * - * @param name test step or group name - * @param time time in millis since start of epoch - * @param status step completion status - * @param command step command - */ - public StepEvent(String name, long time, Status status, String command) { - this.name = name; - this.time = time; - this.status = status; - this.command = command; - } - - /** - * Creates a new step record for non-running status. - * - * @param name test step or group name - * @param status status - * @param command step command - */ - public StepEvent(String name, Status status, String command) { - this(name, System.currentTimeMillis(), status, command); - } - - /** - * Returns the test step or test group name. - * - * @return step or group name - */ - public String name() { - return name; - } - - /** - * Returns the step event time. - * - * @return time in millis since start of epoch - */ - public long time() { - return time; - } - - /** - * Returns the step completion status. - * - * @return completion status - */ - public Status status() { - return status; - } - - /** - * Returns the step command. - * - * @return step command - */ - public String command() { - return command; - } - - - @Override - public String toString() { - return name + SEP + time + SEP + status + SEP + command; - } - - /** - * Returns a record parsed from the specified string. - * - * @param string string encoding - * @return step record - */ - public static StepEvent fromString(String string) { - String[] fields = string.split("~"); - return fields.length == 4 ? - new StepEvent(fields[0], parseLong(fields[1]), valueOf(fields[2]), - fields[3].equals("null") ? null : fields[3]) : - new StepEvent(fields[0], 0, Status.WAITING, null); - } -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessListener.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessListener.java deleted file mode 100644 index a8222d0b..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessListener.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -/** - * Entity capable of receiving notifications of process step execution events. - */ -public interface StepProcessListener { - - /** - * Indicates that process step has started. - * - * @param step subject step - * @param command actual command executed; includes run-time substitutions - */ - default void onStart(Step step, String command) { - } - - /** - * Indicates that process step has completed. - * - * @param step subject step - * @param status step completion status - */ - default void onCompletion(Step step, Coordinator.Status status) { - } - - /** - * Notifies when a new line of output becomes available. - * - * @param step subject step - * @param line line of output - */ - default void onOutput(Step step, String line) { - } - -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java deleted file mode 100644 index 49943691..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import org.onlab.stc.Coordinator.Status; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; - -import static java.lang.String.format; -import static org.onlab.stc.Coordinator.Status.FAILED; -import static org.onlab.stc.Coordinator.Status.SUCCEEDED; -import static org.onlab.stc.Coordinator.print; - -/** - * Manages execution of the specified step or a group. - */ -class StepProcessor implements Runnable { - - private static final String IGNORE_CODE = "~"; - private static final String NEGATE_CODE = "!"; - - private static final int FAIL = -1; - - static String launcher = "stc-launcher "; - - private final Step step; - private final File logDir; - private String command; - - private Process process; - private StepProcessListener delegate; - - /** - * Creates a process monitor. - * - * @param step step or group to be executed - * @param logDir directory where step process log should be stored - * @param delegate process lifecycle listener - * @param command actual command to execute - */ - StepProcessor(Step step, File logDir, StepProcessListener delegate, - String command) { - this.step = step; - this.logDir = logDir; - this.delegate = delegate; - this.command = command; - } - - @Override - public void run() { - delegate.onStart(step, command); - int code = execute(); - boolean ignoreCode = step.env() != null && step.env.equals(IGNORE_CODE); - boolean negateCode = step.env() != null && step.env.equals(NEGATE_CODE); - Status status = ignoreCode || code == 0 && !negateCode || code != 0 && negateCode ? - SUCCEEDED : FAILED; - delegate.onCompletion(step, status); - } - - /** - * Executes the step process. - * - * @return exit code - */ - private int execute() { - try (PrintWriter pw = new PrintWriter(logFile())) { - process = Runtime.getRuntime().exec(command()); - processOutput(pw); - - // Wait for the process to complete and get its exit code. - if (process.isAlive()) { - process.waitFor(); - } - return process.exitValue(); - - } catch (IOException e) { - print("Unable to run step %s using command %s", step.name(), step.command()); - } catch (InterruptedException e) { - print("Step %s interrupted", step.name()); - } - return FAIL; - } - - /** - * Returns ready-to-run command for the step. - * - * @return command to execute - */ - private String command() { - return format("%s %s %s %s", launcher, - step.env() != null ? step.env() : "-", - step.cwd() != null ? step.cwd() : "-", - command); - } - - /** - * Captures output of the step process. - * - * @param pw print writer to send output to - * @throws IOException if unable to read output or write logs - */ - private void processOutput(PrintWriter pw) throws IOException { - InputStream out = process.getInputStream(); - BufferedReader br = new BufferedReader(new InputStreamReader(out)); - - // Slurp its combined stderr/stdout - String line; - while ((line = br.readLine()) != null) { - pw.println(line); - delegate.onOutput(step, line); - } - } - - /** - * Returns the log file for the step output. - * - * @return log file - */ - private File logFile() { - return new File(logDir, step.name() + ".log"); - } - -} diff --git a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/package-info.java b/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/package-info.java deleted file mode 100644 index 56145899..00000000 --- a/framework/src/onos/utils/stc/src/main/java/org/onlab/stc/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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. - */ - -/** - * System Test Coordinator tool for modular scenario-based testing. - */ -package org.onlab.stc;
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/main/resources/data.json b/framework/src/onos/utils/stc/src/main/resources/data.json deleted file mode 100644 index f5823744..00000000 --- a/framework/src/onos/utils/stc/src/main/resources/data.json +++ /dev/null @@ -1,1087 +0,0 @@ -{ - "requirements": [ - { - "dst": "Reactive-Forwarding.Ping-2", - "isSoft": false, - "src": "Reactive-Forwarding.Link-2-Down" - }, - { - "dst": "Final-Check-Logs-2", - "isSoft": true, - "src": "Fetch-Logs-2" - }, - { - "dst": "Host-Intent.Ping-4", - "isSoft": false, - "src": "Host-Intent.Link-2-Up" - }, - { - "dst": "Install-1", - "isSoft": false, - "src": "Wait-for-Start-1" - }, - { - "dst": "Host-Intent.Link-1-Down", - "isSoft": false, - "src": "Host-Intent.Ping-2" - }, - { - "dst": "Host-Intent.Link-2-Up", - "isSoft": false, - "src": "Host-Intent.Ping-5" - }, - { - "dst": "Host-Intent.Ping-2", - "isSoft": false, - "src": "Host-Intent.Link-2-Down" - }, - { - "dst": "Reinstall-App-With-CLI", - "isSoft": false, - "src": "Verify-CLI" - }, - { - "dst": "Create-App-UI-Overlay", - "isSoft": false, - "src": "Build-App-With-UI" - }, - { - "dst": "Secure-SSH", - "isSoft": true, - "src": "Wait-for-Start-1" - }, - { - "dst": "Pause-For-Masters", - "isSoft": true, - "src": "Check-Flows" - }, - { - "dst": "Secure-SSH", - "isSoft": true, - "src": "Wait-for-Start-3" - }, - { - "dst": "Uninstall-3", - "isSoft": false, - "src": "Kill-3" - }, - { - "dst": "Balance-Masters", - "isSoft": false, - "src": "Pause-For-Masters" - }, - { - "dst": "Reactive-Forwarding.Net-Pingall", - "isSoft": true, - "src": "Reactive-Forwarding.Net-Link-Down-Up" - }, - { - "dst": "Wait-for-Start-3", - "isSoft": true, - "src": "Check-Logs-3" - }, - { - "dst": "Wait-for-Start-2", - "isSoft": true, - "src": "Check-Components-2" - }, - { - "dst": "Uninstall-Reactive-Forwarding", - "isSoft": false, - "src": "Find-Host-1" - }, - { - "dst": "Wipe-Out-Data-Before", - "isSoft": true, - "src": "Initial-Summary-Check" - }, - { - "dst": "Reactive-Forwarding.Ping-3", - "isSoft": false, - "src": "Reactive-Forwarding.Link-1-Up" - }, - { - "dst": "Archetypes", - "isSoft": true, - "src": "Wrapup" - }, - { - "dst": "Reactive-Forwarding.Ping-4", - "isSoft": false, - "src": "Reactive-Forwarding.Link-2-Up" - }, - { - "dst": "Host-Intent-Connectivity", - "isSoft": true, - "src": "Net-Teardown" - }, - { - "dst": "Host-Intent.Ping-3", - "isSoft": false, - "src": "Host-Intent.Link-1-Up" - }, - { - "dst": "Host-Intent.Ping-1", - "isSoft": false, - "src": "Host-Intent.Link-1-Down" - }, - { - "dst": "Install-App", - "isSoft": false, - "src": "Create-App-CLI-Overlay" - }, - { - "dst": "Final-Check-Logs-3", - "isSoft": true, - "src": "Fetch-Logs-3" - }, - { - "dst": "Install-App", - "isSoft": false, - "src": "Verify-App" - }, - { - "dst": "Host-Intent.Link-2-Down", - "isSoft": false, - "src": "Host-Intent.Ping-3" - }, - { - "dst": "Prerequisites", - "isSoft": false, - "src": "Setup" - }, - { - "dst": "Verify-App", - "isSoft": true, - "src": "Reinstall-App-With-CLI" - }, - { - "dst": "Net-Smoke", - "isSoft": true, - "src": "Archetypes" - }, - { - "dst": "Setup", - "isSoft": true, - "src": "Wrapup" - }, - { - "dst": "Start-Mininet", - "isSoft": false, - "src": "Wait-For-Mininet" - }, - { - "dst": "Verify-UI", - "isSoft": false, - "src": "Uninstall-App" - }, - { - "dst": "Kill-3", - "isSoft": false, - "src": "Install-3" - }, - { - "dst": "Wait-for-Start-1", - "isSoft": true, - "src": "Check-Components-1" - }, - { - "dst": "Wait-for-Start-1", - "isSoft": true, - "src": "Check-Nodes-1" - }, - { - "dst": "Push-Topos", - "isSoft": false, - "src": "Start-Mininet" - }, - { - "dst": "Reactive-Forwarding.Check-Summary-For-Hosts", - "isSoft": true, - "src": "Reactive-Forwarding.Config-Topo" - }, - { - "dst": "Reactive-Forwarding.Install-Apps", - "isSoft": false, - "src": "Reactive-Forwarding.Check-Apps" - }, - { - "dst": "Push-Bits", - "isSoft": false, - "src": "Install-2" - }, - { - "dst": "Install-1", - "isSoft": false, - "src": "Secure-SSH" - }, - { - "dst": "Create-Intent", - "isSoft": false, - "src": "Host-Intent.Net-Link-Down-Up" - }, - { - "dst": "Verify-CLI", - "isSoft": true, - "src": "Reinstall-App-With-UI" - }, - { - "dst": "Wait-for-Start-3", - "isSoft": true, - "src": "Check-Apps-3" - }, - { - "dst": "Net-Smoke", - "isSoft": true, - "src": "Wrapup" - }, - { - "dst": "Initial-Summary-Check", - "isSoft": false, - "src": "Start-Mininet" - }, - { - "dst": "Install-3", - "isSoft": false, - "src": "Wait-for-Start-3" - }, - { - "dst": "Reactive-Forwarding.Link-1-Up", - "isSoft": false, - "src": "Reactive-Forwarding.Ping-4" - }, - { - "dst": "Check-Summary", - "isSoft": true, - "src": "Balance-Masters" - }, - { - "dst": "Reactive-Forwarding.Net-Link-Down-Up", - "isSoft": true, - "src": "Host-Intent-Connectivity" - }, - { - "dst": "Secure-SSH", - "isSoft": true, - "src": "Wait-for-Start-2" - }, - { - "dst": "Build-App-With-CLI", - "isSoft": false, - "src": "Reinstall-App-With-CLI" - }, - { - "dst": "Uninstall-1", - "isSoft": false, - "src": "Kill-1" - }, - { - "dst": "Find-Host-1", - "isSoft": false, - "src": "Find-Host-2" - }, - { - "dst": "Create-App-CLI-Overlay", - "isSoft": false, - "src": "Build-App-With-CLI" - }, - { - "dst": "Net-Setup", - "isSoft": false, - "src": "Reactive-Forwarding.Net-Link-Down-Up" - }, - { - "dst": "Kill-2", - "isSoft": false, - "src": "Install-2" - }, - { - "dst": "Wait-for-Start-1", - "isSoft": true, - "src": "Check-Logs-1" - }, - { - "dst": "Wait-for-Start-2", - "isSoft": true, - "src": "Check-Nodes-2" - }, - { - "dst": "Reactive-Forwarding.Ping-All-And-Verify", - "isSoft": true, - "src": "Reactive-Forwarding.Check-Summary-For-Hosts" - }, - { - "dst": "Clean-Up", - "isSoft": false, - "src": "Create-App" - }, - { - "dst": "Host-Intent.Link-1-Up", - "isSoft": false, - "src": "Host-Intent.Ping-4" - }, - { - "dst": "Build-App-With-UI", - "isSoft": false, - "src": "Reinstall-App-With-UI" - }, - { - "dst": "Install-2", - "isSoft": false, - "src": "Secure-SSH" - }, - { - "dst": "Wait-For-Mininet", - "isSoft": false, - "src": "Check-Summary" - }, - { - "dst": "Host-Intent.Net-Link-Down-Up", - "isSoft": false, - "src": "Remove-Intent" - }, - { - "dst": "Net-Setup", - "isSoft": false, - "src": "Host-Intent-Connectivity" - }, - { - "dst": "Net-Setup", - "isSoft": false, - "src": "Reactive-Forwarding.Net-Pingall" - }, - { - "dst": "Reactive-Forwarding.Link-2-Down", - "isSoft": false, - "src": "Reactive-Forwarding.Ping-3" - }, - { - "dst": "Find-Host-2", - "isSoft": false, - "src": "Create-Intent" - }, - { - "dst": "Wait-for-Start-2", - "isSoft": true, - "src": "Check-Apps-2" - }, - { - "dst": "Final-Check-Logs-1", - "isSoft": true, - "src": "Fetch-Logs-1" - }, - { - "dst": "Install-2", - "isSoft": false, - "src": "Wait-for-Start-2" - }, - { - "dst": "Reactive-Forwarding.Ping-1", - "isSoft": false, - "src": "Reactive-Forwarding.Link-1-Down" - }, - { - "dst": "Create-App", - "isSoft": false, - "src": "Build-App" - }, - { - "dst": "Check-Summary", - "isSoft": true, - "src": "Check-Flows" - }, - { - "dst": "Build-App", - "isSoft": false, - "src": "Install-App" - }, - { - "dst": "Reinstall-App-With-UI", - "isSoft": false, - "src": "Verify-UI" - }, - { - "dst": "Uninstall-2", - "isSoft": false, - "src": "Kill-2" - }, - { - "dst": "Setup", - "isSoft": false, - "src": "Archetypes" - }, - { - "dst": "Setup", - "isSoft": false, - "src": "Net-Smoke" - }, - { - "dst": "Kill-1", - "isSoft": false, - "src": "Install-1" - }, - { - "dst": "Reactive-Forwarding.Link-1-Down", - "isSoft": false, - "src": "Reactive-Forwarding.Ping-2" - }, - { - "dst": "Wait-for-Start-2", - "isSoft": true, - "src": "Check-Logs-2" - }, - { - "dst": "Wait-for-Start-3", - "isSoft": true, - "src": "Check-Components-3" - }, - { - "dst": "Wait-for-Start-3", - "isSoft": true, - "src": "Check-Nodes-3" - }, - { - "dst": "Stop-Mininet-If-Needed", - "isSoft": false, - "src": "Start-Mininet" - }, - { - "dst": "Reactive-Forwarding.Link-2-Up", - "isSoft": false, - "src": "Reactive-Forwarding.Ping-5" - }, - { - "dst": "Reactive-Forwarding.Check-Apps", - "isSoft": false, - "src": "Reactive-Forwarding.Ping-All-And-Verify" - }, - { - "dst": "Install-3", - "isSoft": false, - "src": "Secure-SSH" - }, - { - "dst": "Push-Bits", - "isSoft": false, - "src": "Install-3" - }, - { - "dst": "Reinstall-App-With-CLI", - "isSoft": false, - "src": "Create-App-UI-Overlay" - }, - { - "dst": "Push-Bits", - "isSoft": false, - "src": "Install-1" - }, - { - "dst": "Wait-for-Start-1", - "isSoft": true, - "src": "Check-Apps-1" - } - ], - "steps": [ - { - "group": "Net-Setup", - "isGroup": false, - "name": "Check-Summary", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Check-Flows", - "status": "waiting" - }, - { - "group": "Wrapup", - "isGroup": false, - "name": "Final-Check-Logs-1", - "status": "waiting" - }, - { - "group": "Wrapup", - "isGroup": false, - "name": "Final-Check-Logs-2", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Clean-Up", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Build-App-With-UI", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Uninstall-App", - "status": "waiting" - }, - { - "group": "Wrapup", - "isGroup": false, - "name": "Final-Check-Logs-3", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Link-2-Down", - "status": "waiting" - }, - { - "group": "Wrapup", - "isGroup": false, - "name": "Fetch-Logs-3", - "status": "waiting" - }, - { - "group": "Wrapup", - "isGroup": false, - "name": "Fetch-Logs-2", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Components-3", - "status": "waiting" - }, - { - "group": "Wrapup", - "isGroup": false, - "name": "Fetch-Logs-1", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Push-Topos", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Pingall", - "isGroup": false, - "name": "Reactive-Forwarding.Check-Apps", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Wait-for-Start-3", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Wait-for-Start-2", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Wait-for-Start-1", - "status": "waiting" - }, - { - "group": "Net-Smoke", - "isGroup": true, - "name": "Host-Intent-Connectivity", - "status": "waiting" - }, - { - "group": "Host-Intent-Connectivity", - "isGroup": false, - "name": "Create-Intent", - "status": "waiting" - }, - { - "isGroup": true, - "name": "Prerequisites", - "status": "in_progress" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Push-Bits", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Logs-2", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Logs-3", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Kill-1", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Kill-3", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Kill-2", - "status": "waiting" - }, - { - "group": "Host-Intent-Connectivity", - "isGroup": true, - "name": "Host-Intent.Net-Link-Down-Up", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Ping-1", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Verify-UI", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Ping-2", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Ping-3", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Uninstall-1", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Logs-1", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Ping-4", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Uninstall-3", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Ping-5", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Uninstall-2", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Pingall", - "isGroup": false, - "name": "Reactive-Forwarding.Install-Apps", - "status": "waiting" - }, - { - "group": "Net-Smoke", - "isGroup": true, - "name": "Reactive-Forwarding.Net-Link-Down-Up", - "status": "waiting" - }, - { - "group": "Prerequisites", - "isGroup": false, - "name": "Check-ONOS-Bits", - "status": "in_progress" - }, - { - "isGroup": true, - "name": "Wrapup", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Install-2", - "status": "waiting" - }, - { - "group": "Host-Intent-Connectivity", - "isGroup": false, - "name": "Find-Host-1", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Install-1", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Wipe-Out-Data-Before", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Pause-For-Masters", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Link-2-Up", - "status": "waiting" - }, - { - "group": "Net-Smoke", - "isGroup": true, - "name": "Reactive-Forwarding.Net-Pingall", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Components-2", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Components-1", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Reinstall-App-With-UI", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Reinstall-App-With-CLI", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Build-App-With-CLI", - "status": "waiting" - }, - { - "group": "Host-Intent-Connectivity", - "isGroup": false, - "name": "Uninstall-Reactive-Forwarding", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Link-2-Up", - "status": "waiting" - }, - { - "group": "Net-Teardown", - "isGroup": false, - "name": "Stop-Mininet", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Pingall", - "isGroup": false, - "name": "Reactive-Forwarding.Config-Topo", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Create-App-CLI-Overlay", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Link-1-Down", - "status": "waiting" - }, - { - "isGroup": true, - "name": "Net-Smoke", - "status": "waiting" - }, - { - "group": "Prerequisites", - "isGroup": false, - "name": "Check-Passwordless-Login-2", - "status": "in_progress" - }, - { - "group": "Prerequisites", - "isGroup": false, - "name": "Check-Passwordless-Login-1", - "status": "in_progress" - }, - { - "group": "Prerequisites", - "isGroup": false, - "name": "Check-Passwordless-Login-3", - "status": "in_progress" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Secure-SSH", - "status": "waiting" - }, - { - "group": "Net-Smoke", - "isGroup": true, - "name": "Net-Setup", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Nodes-1", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Install-3", - "status": "waiting" - }, - { - "group": "Host-Intent-Connectivity", - "isGroup": false, - "name": "Find-Host-2", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Initial-Summary-Check", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Create-App", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Nodes-3", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Nodes-2", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Link-2-Down", - "status": "waiting" - }, - { - "isGroup": true, - "name": "Setup", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Verify-App", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Ping-1", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Ping-2", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Start-Mininet", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Ping-3", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Ping-4", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Ping-5", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Verify-CLI", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Pingall", - "isGroup": false, - "name": "Reactive-Forwarding.Check-Summary-For-Hosts", - "status": "waiting" - }, - { - "group": "Net-Smoke", - "isGroup": true, - "name": "Net-Teardown", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Link-1-Up", - "status": "waiting" - }, - { - "group": "Host-Intent-Connectivity", - "isGroup": false, - "name": "Remove-Intent", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Install-App", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Create-App-UI-Overlay", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Link-Down-Up", - "isGroup": false, - "name": "Reactive-Forwarding.Link-1-Up", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Wait-For-Mininet", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Apps-3", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Apps-2", - "status": "waiting" - }, - { - "group": "Setup", - "isGroup": false, - "name": "Check-Apps-1", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Stop-Mininet-If-Needed", - "status": "waiting" - }, - { - "group": "Prerequisites", - "isGroup": false, - "name": "Check-Environment", - "status": "in_progress" - }, - { - "isGroup": true, - "name": "Archetypes", - "status": "waiting" - }, - { - "group": "Host-Intent.Net-Link-Down-Up", - "isGroup": false, - "name": "Host-Intent.Link-1-Down", - "status": "waiting" - }, - { - "group": "Net-Setup", - "isGroup": false, - "name": "Balance-Masters", - "status": "waiting" - }, - { - "group": "Reactive-Forwarding.Net-Pingall", - "isGroup": false, - "name": "Reactive-Forwarding.Ping-All-And-Verify", - "status": "waiting" - }, - { - "group": "Archetypes", - "isGroup": false, - "name": "Build-App", - "status": "waiting" - } - ] -} diff --git a/framework/src/onos/utils/stc/src/main/resources/index.html b/framework/src/onos/utils/stc/src/main/resources/index.html deleted file mode 100644 index c75bb8f2..00000000 --- a/framework/src/onos/utils/stc/src/main/resources/index.html +++ /dev/null @@ -1,29 +0,0 @@ -<!DOCTYPE html> -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<html> -<head lang="en"> - <meta charset="utf-8"> - <title>Scenario Test Coordinator</title> - - <link rel="stylesheet" href="stc.css"> - - <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> - <script src="stc.js"></script> -</head> -<body> -</body> -</html>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/main/resources/stc.css b/framework/src/onos/utils/stc/src/main/resources/stc.css deleted file mode 100644 index 8d94253e..00000000 --- a/framework/src/onos/utils/stc/src/main/resources/stc.css +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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. - */ - -.body { - font-family: Helvetica, Arial, sans-serif; -} - -.node { - stroke: #fff; - stroke-width: 1.5px; -} - -.link { - stroke: #999; - stroke-opacity: .6; -} - -text { - font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif; - stroke: #000; - stroke-width: 0.2; - font-weight: normal; - font-size: 0.6em; -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/main/resources/stc.js b/framework/src/onos/utils/stc/src/main/resources/stc.js deleted file mode 100644 index 215fd6e2..00000000 --- a/framework/src/onos/utils/stc/src/main/resources/stc.js +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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. - */ -(function () { - - var ws, flow, - nodes = [], - links = [], - nodeIndexes = {}; - - var width = 2400, - height = 2400; - - var color = d3.scale.category20(); - - var force = d3.layout.force() - .charge(-820) - .linkDistance(50) - .size([width, height]); - - // Process flow graph layout - function createNode(n) { - nodeIndexes[n.name] = nodes.push(n) - 1; - } - - function createLink(e) { - e.source = nodeIndexes[e.src]; - e.target = nodeIndexes[e.dst]; - links.push(e); - } - - // Returns the newly computed bounding box of the rectangle - function adjustRectToFitText(n) { - var text = n.select('text'), - box = text.node().getBBox(); - - text.attr('text-anchor', 'left') - .attr('y', 2) - .attr('x', 4); - - // add padding - box.x -= 4; - box.width += 8; - box.y -= 2; - box.height += 4; - - n.select("rect").attr(box); - } - - function processFlow() { - var svg = d3.select("body").append("svg") - .attr("width", width) - .attr("height", height); - - flow.steps.forEach(createNode); - flow.requirements.forEach(createLink); - - force - .nodes(nodes) - .links(links) - .start(); - - var link = svg.selectAll(".link") - .data(links) - .enter().append("line") - .attr("class", "link") - .style("stroke-width", function(d) { return d.isSoft ? 1 : 2; }); - - var node = svg.selectAll(".node") - .data(nodes) - .enter().append("g") - .attr("class", "node") - .call(force.drag); - - node.append("rect") - .attr({ rx: 5, ry:5, width:180, height:18 }) - .style("fill", function(d) { return color(d.group); }); - - node.append("text").text( function(d) { return d.name; }) - .attr({ dy:"1.1em", width:100, height:16, x:4, y:2 }); - - node.append("title") - .text(function(d) { return d.name; }); - - force.on("tick", function() { - link.attr("x1", function(d) { return d.source.x; }) - .attr("y1", function(d) { return d.source.y; }) - .attr("x2", function(d) { return d.target.x; }) - .attr("y2", function(d) { return d.target.y; }); - - node.attr("transform", function(d) { return "translate(" + (d.x - 180/2) + "," + (d.y - 18/2) + ")"; }); - }); - } - - - // Web socket callbacks - - function handleOpen() { - console.log('WebSocket open'); - } - - // Handles the specified (incoming) message using handler bindings. - function handleMessage(msg) { - console.log('rx: ', msg); - evt = JSON.parse(msg.data); - if (evt.event === 'progress') { - - } else if (evt.event === 'log') { - - } else if (evt.event === 'flow') { - flow = evt.payload; - processFlow(); - } - } - - function handleClose() { - console.log('WebSocket closed'); - } - - if (false) { - d3.json("data.json", function (error, data) { - flow = data; - processFlow(); - }); - return; - } - - // Open the web-socket - ws = new WebSocket(document.location.href.replace('http:', 'ws:')); - if (ws) { - ws.onopen = handleOpen; - ws.onmessage = handleMessage; - ws.onclose = handleClose; - } - -})();
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CompilerTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CompilerTest.java deleted file mode 100644 index 59b55307..00000000 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CompilerTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.io.Files; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; - -import static com.google.common.io.ByteStreams.toByteArray; -import static com.google.common.io.Files.write; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.onlab.stc.Scenario.loadScenario; - -/** - * Test of the test scenario compiler. - */ -public class CompilerTest { - - static final File TEST_DIR = Files.createTempDir(); - - @BeforeClass - public static void setUpClass() throws IOException { - stageTestResource("scenario.xml"); - stageTestResource("simple-scenario.xml"); - stageTestResource("one-scenario.xml"); - stageTestResource("two-scenario.xml"); - - System.setProperty("prop.foo", "Foobar"); - System.setProperty("prop.bar", "Barfoo"); - System.setProperty("TOC1", "1.2.3.1"); - System.setProperty("TOC2", "1.2.3.2"); - System.setProperty("TOC3", "1.2.3.3"); - System.setProperty("test.dir", TEST_DIR.getAbsolutePath()); - } - - static FileInputStream getStream(String name) throws FileNotFoundException { - return new FileInputStream(new File(TEST_DIR, name)); - } - - static void stageTestResource(String name) throws IOException { - byte[] bytes = toByteArray(CompilerTest.class.getResourceAsStream(name)); - write(bytes, new File(TEST_DIR, name)); - } - - @Test - public void basics() throws Exception { - Scenario scenario = loadScenario(getStream("scenario.xml")); - Compiler compiler = new Compiler(scenario); - compiler.compile(); - ProcessFlow flow = compiler.processFlow(); - - assertSame("incorrect scenario", scenario, compiler.scenario()); - assertEquals("incorrect step count", 33, flow.getVertexes().size()); - assertEquals("incorrect dependency count", 26, flow.getEdges().size()); - assertEquals("incorrect logDir", - new File(TEST_DIR.getAbsolutePath(), "foo"), compiler.logDir()); - - Step step = compiler.getStep("there"); - assertEquals("incorrect edge count", 2, flow.getEdgesFrom(step).size()); - assertEquals("incorrect edge count", 0, flow.getEdgesTo(step).size()); - - Step group = compiler.getStep("three"); - assertEquals("incorrect edge count", 2, flow.getEdgesFrom(group).size()); - assertEquals("incorrect edge count", 0, flow.getEdgesTo(group).size()); - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CoordinatorTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CoordinatorTest.java deleted file mode 100644 index c6f057ec..00000000 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/CoordinatorTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.util.Tools; - -import java.io.IOException; - -import static org.onlab.stc.CompilerTest.getStream; -import static org.onlab.stc.Coordinator.print; -import static org.onlab.stc.Scenario.loadScenario; - -/** - * Test of the test coordinator. - */ -public class CoordinatorTest { - - private Coordinator coordinator; - private StepProcessListener listener = new Listener(); - - @BeforeClass - public static void setUpClass() throws IOException { - CompilerTest.setUpClass(); - Tools.removeDirectory(StepProcessorTest.DIR); - - StepProcessor.launcher = "true "; - } - - @Test - public void simple() throws IOException, InterruptedException { - executeTest("simple-scenario.xml"); - } - - @Test - public void complex() throws IOException, InterruptedException { - executeTest("scenario.xml"); - } - - private void executeTest(String name) throws IOException, InterruptedException { - Scenario scenario = loadScenario(getStream(name)); - Compiler compiler = new Compiler(scenario); - compiler.compile(); - Tools.removeDirectory(compiler.logDir()); - coordinator = new Coordinator(scenario, compiler.processFlow(), compiler.logDir()); - coordinator.addListener(listener); - coordinator.reset(); - coordinator.start(); - coordinator.waitFor(); - coordinator.removeListener(listener); - } - - private class Listener implements StepProcessListener { - @Override - public void onStart(Step step, String command) { - print("> %s: started; %s", step.name(), command); - } - - @Override - public void onCompletion(Step step, Coordinator.Status status) { - print("< %s: %s", step.name(), status == Coordinator.Status.SUCCEEDED ? "completed" : "failed"); - } - - @Override - public void onOutput(Step step, String line) { - print(" %s: %s", step.name(), line); - } - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/DependencyTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/DependencyTest.java deleted file mode 100644 index 4438303c..00000000 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/DependencyTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.testing.EqualsTester; -import org.apache.commons.configuration.ConfigurationException; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Test of the test step dependency. - */ -public class DependencyTest extends StepTest { - - protected Step step1, step2; - - @Before - public void setUp() throws ConfigurationException { - super.setUp(); - step1 = new Step("step1", CMD, null, null, null); - step2 = new Step("step2", CMD, null, null, null); - } - - @Test - public void hard() { - Dependency hard = new Dependency(step1, step2, false); - assertSame("incorrect src", step1, hard.src()); - assertSame("incorrect dst", step2, hard.dst()); - assertFalse("incorrect isSoft", hard.isSoft()); - } - - @Test - public void soft() { - Dependency soft = new Dependency(step2, step1, true); - assertSame("incorrect src", step2, soft.src()); - assertSame("incorrect dst", step1, soft.dst()); - assertTrue("incorrect isSoft", soft.isSoft()); - } - - @Test - public void equality() { - Dependency d1 = new Dependency(step1, step2, false); - Dependency d2 = new Dependency(step1, step2, false); - Dependency d3 = new Dependency(step1, step2, true); - Dependency d4 = new Dependency(step2, step1, true); - new EqualsTester() - .addEqualityGroup(d1, d2) - .addEqualityGroup(d3) - .addEqualityGroup(d4) - .testEquals(); - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/GroupTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/GroupTest.java deleted file mode 100644 index 9b612c85..00000000 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/GroupTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.testing.EqualsTester; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; - -/** - * Test of the test scenario entity. - */ -public class GroupTest extends StepTest { - - @Test - public void basics() { - Group group = new Group(NAME, CMD, ENV, CWD, parent); - assertEquals("incorrect name", NAME, group.name()); - assertEquals("incorrect command", CMD, group.command()); - assertEquals("incorrect env", ENV, group.env()); - assertEquals("incorrect cwd", CWD, group.cwd()); - assertSame("incorrect group", parent, group.group()); - - Step step = new Step("step", null, null, null, group); - group.addChild(step); - assertSame("incorrect child", step, group.children().iterator().next()); - } - - @Test - public void equality() { - Group g1 = new Group(NAME, CMD, null, null, parent); - Group g2 = new Group(NAME, CMD, ENV, CWD, null); - Group g3 = new Group("foo", null, null, null, parent); - new EqualsTester() - .addEqualityGroup(g1, g2) - .addEqualityGroup(g3) - .testEquals(); - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/MonitorLayoutTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/MonitorLayoutTest.java deleted file mode 100644 index 4b7f5614..00000000 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/MonitorLayoutTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import org.junit.Test; -import org.onlab.stc.MonitorLayout.Box; - -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.onlab.stc.CompilerTest.getStream; -import static org.onlab.stc.CompilerTest.stageTestResource; -import static org.onlab.stc.MonitorLayout.SLOT_WIDTH; -import static org.onlab.stc.Scenario.loadScenario; - -/** - * Tests of the monitor layout functionality. - */ -public class MonitorLayoutTest { - - private MonitorLayout layout; - - private Compiler getCompiler(String name) throws IOException { - stageTestResource(name); - Scenario scenario = loadScenario(getStream(name)); - Compiler compiler = new Compiler(scenario); - compiler.compile(); - return compiler; - } - - @Test - public void basic() throws IOException { - layout = new MonitorLayout(getCompiler("layout-basic.xml")); - validate(layout, null, 0, 1, 5, 2); - validate(layout, "a", 1, 1, 1, 1, 1, -SLOT_WIDTH / 2); - validate(layout, "b", 2, 2, 1, 1, 0, 0); - validate(layout, "f", 3, 3, 1); - - validate(layout, "g", 1, 1, 4, 1, 1, SLOT_WIDTH / 2); - validate(layout, "c", 2, 1, 1); - validate(layout, "d", 3, 2, 1); - validate(layout, "e", 4, 3, 1); - } - - @Test - public void basicNest() throws IOException { - layout = new MonitorLayout(getCompiler("layout-basic-nest.xml")); - validate(layout, null, 0, 1, 6, 2); - validate(layout, "a", 1, 1, 1, 1, 1, -SLOT_WIDTH / 2); - validate(layout, "b", 2, 2, 1); - validate(layout, "f", 3, 3, 1); - - validate(layout, "g", 1, 1, 5, 1); - validate(layout, "c", 2, 1, 1); - - validate(layout, "gg", 3, 2, 3, 1); - validate(layout, "d", 4, 1, 1); - validate(layout, "e", 5, 2, 1); - } - - @Test - public void staggeredDependencies() throws IOException { - layout = new MonitorLayout(getCompiler("layout-staggered-dependencies.xml")); - validate(layout, null, 0, 1, 7, 4); - validate(layout, "a", 1, 1, 1, 1, 1, -SLOT_WIDTH - SLOT_WIDTH / 2); - validate(layout, "aa", 1, 1, 1, 1, 1, -SLOT_WIDTH / 2); - validate(layout, "b", 2, 2, 1); - validate(layout, "f", 3, 3, 1); - - validate(layout, "g", 1, 1, 5, 2, 1, +SLOT_WIDTH / 2); - validate(layout, "c", 2, 1, 1); - - validate(layout, "gg", 3, 2, 3, 2); - validate(layout, "d", 4, 1, 1); - validate(layout, "dd", 4, 1, 1); - validate(layout, "e", 5, 2, 1); - - validate(layout, "i", 6, 6, 1); - } - - @Test - public void deepNext() throws IOException { - layout = new MonitorLayout(getCompiler("layout-deep-nest.xml")); - validate(layout, null, 0, 1, 7, 6); - validate(layout, "a", 1, 1, 1); - validate(layout, "aa", 1, 1, 1); - validate(layout, "b", 2, 2, 1); - validate(layout, "f", 3, 3, 1); - - validate(layout, "g", 1, 1, 5, 2); - validate(layout, "c", 2, 1, 1); - - validate(layout, "gg", 3, 2, 3, 2); - validate(layout, "d", 4, 1, 1); - validate(layout, "dd", 4, 1, 1); - validate(layout, "e", 5, 2, 1); - - validate(layout, "i", 6, 6, 1); - - validate(layout, "g1", 1, 1, 6, 2); - validate(layout, "g2", 2, 1, 5, 2); - validate(layout, "g3", 3, 1, 4, 2); - validate(layout, "u", 4, 1, 1); - validate(layout, "v", 4, 1, 1); - validate(layout, "w", 5, 2, 1); - validate(layout, "z", 6, 3, 1); - } - - - private void validate(MonitorLayout layout, String name, - int absoluteTier, int tier, int depth, int breadth) { - Box b = layout.get(name); - assertEquals("incorrect absolute tier", absoluteTier, b.absoluteTier()); - assertEquals("incorrect tier", tier, b.tier()); - assertEquals("incorrect depth", depth, b.depth()); - assertEquals("incorrect breadth", breadth, b.breadth()); - } - - private void validate(MonitorLayout layout, String name, - int absoluteTier, int tier, int depth, int breadth, - int top, int center) { - validate(layout, name, absoluteTier, tier, depth, breadth); - Box b = layout.get(name); - assertEquals("incorrect top", top, b.top()); - assertEquals("incorrect center", center, b.center()); - } - - private void validate(MonitorLayout layout, String name, - int absoluteTier, int tier, int depth) { - validate(layout, name, absoluteTier, tier, depth, 1); - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/ScenarioTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/ScenarioTest.java deleted file mode 100644 index 2aa51747..00000000 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/ScenarioTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import org.apache.commons.configuration.ConfigurationException; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.onlab.stc.Scenario.loadScenario; - -/** - * Test of the test scenario entity. - */ -public class ScenarioTest { - - @Test - public void basics() throws ConfigurationException { - Scenario scenario = loadScenario(getClass().getResourceAsStream("scenario.xml")); - assertEquals("incorrect name", "foo", scenario.name()); - assertEquals("incorrect description", "Test Scenario", scenario.description()); - assertEquals("incorrect logDir", "Test Scenario", scenario.description()); - assertEquals("incorrect definition", "Test Scenario", - scenario.definition().getString("[@description]")); - } - - @Test(expected = IllegalArgumentException.class) - public void badStream() throws ConfigurationException { - loadScenario(getClass().getResourceAsStream("no.xml")); - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/StepProcessorTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/StepProcessorTest.java deleted file mode 100644 index 74d50241..00000000 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/StepProcessorTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.io.Files; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onlab.util.Tools; - -import java.io.File; -import java.io.IOException; - -import static com.google.common.base.Preconditions.checkState; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.onlab.stc.Coordinator.Status.SUCCEEDED; - -/** - * Test of the step processor. - */ -public class StepProcessorTest { - - static final File DIR = Files.createTempDir(); - private final Listener delegate = new Listener(); - - @BeforeClass - public static void setUpClass() { - StepProcessor.launcher = "echo"; - checkState(DIR.exists() || DIR.mkdirs(), "Unable to create directory"); - } - - @AfterClass - public static void tearDownClass() throws IOException { - Tools.removeDirectory(DIR.getPath()); - } - - @Test - public void basics() { - Step step = new Step("foo", "ls " + DIR.getAbsolutePath(), null, null, null); - StepProcessor processor = new StepProcessor(step, DIR, delegate, step.command()); - processor.run(); - assertTrue("should be started", delegate.started); - assertTrue("should be stopped", delegate.stopped); - assertEquals("incorrect status", SUCCEEDED, delegate.status); - assertTrue("should have output", delegate.output); - } - - private class Listener implements StepProcessListener { - - private Coordinator.Status status; - private boolean started, stopped, output; - - @Override - public void onStart(Step step, String command) { - started = true; - } - - @Override - public void onCompletion(Step step, Coordinator.Status status) { - stopped = true; - this.status = status; - } - - @Override - public void onOutput(Step step, String line) { - output = true; - } - } - -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/StepTest.java b/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/StepTest.java deleted file mode 100644 index 71083624..00000000 --- a/framework/src/onos/utils/stc/src/test/java/org/onlab/stc/StepTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 Open Networking Laboratory - * - * 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.onlab.stc; - -import com.google.common.testing.EqualsTester; -import org.apache.commons.configuration.ConfigurationException; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; - -/** - * Test of the test step entity. - */ -public class StepTest { - - protected static final String NAME = "step"; - protected static final String CMD = "command"; - protected static final String ENV = "environment"; - protected static final String CWD = "directory"; - protected Group parent; - - @Before - public void setUp() throws ConfigurationException { - parent = new Group("parent", null, null, null, null); - } - - @Test - public void basics() { - Step step = new Step(NAME, CMD, ENV, CWD, parent); - assertEquals("incorrect name", NAME, step.name()); - assertEquals("incorrect command", CMD, step.command()); - assertEquals("incorrect env", ENV, step.env()); - assertEquals("incorrect cwd", CWD, step.cwd()); - assertSame("incorrect group", parent, step.group()); - } - - @Test - public void equality() { - Step s1 = new Step(NAME, CMD, null, null, parent); - Step s2 = new Step(NAME, CMD, ENV, CWD, null); - Step s3 = new Step("foo", null, null, null, parent); - new EqualsTester() - .addEqualityGroup(s1, s2) - .addEqualityGroup(s3) - .testEquals(); - } -}
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-basic-nest.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-basic-nest.xml deleted file mode 100644 index 19c48db1..00000000 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-basic-nest.xml +++ /dev/null @@ -1,27 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<scenario name="basic-nest"> - <step name="a"/> - <step name="b" requires="a"/> - <step name="f" requires="b"/> - <group name="g"> - <step name="c"/> - <group name="gg" requires="c"> - <step name="d"/> - <step name="e" requires="d"/> - </group> - </group> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-basic.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-basic.xml deleted file mode 100644 index d7dc1383..00000000 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-basic.xml +++ /dev/null @@ -1,25 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<scenario name="basic"> - <step name="a"/> - <step name="b" requires="a"/> - <step name="f" requires="b"/> - <group name="g"> - <step name="c"/> - <step name="d" requires="c"/> - <step name="e" requires="d"/> - </group> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-deep-nest.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-deep-nest.xml deleted file mode 100644 index bbe1ac19..00000000 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-deep-nest.xml +++ /dev/null @@ -1,41 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<scenario name="basic-nest"> - <step name="a"/> - <step name="aa"/> - <step name="b" requires="a"/> - <step name="f" requires="b,aa"/> - <group name="g"> - <step name="c"/> - <group name="gg" requires="c"> - <step name="d"/> - <step name="dd" requires="c"/> - <step name="e" requires="d"/> - </group> - </group> - <step name="i" requires="f,g"/> - - <group name="g1"> - <group name="g2"> - <group name="g3"> - <step name="u"/> - <step name="v"/> - <step name="w" requires="u,v"/> - <step name="z" requires="u,w"/> - </group> - </group> - </group> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-staggered-dependencies.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-staggered-dependencies.xml deleted file mode 100644 index 318b4ba1..00000000 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/layout-staggered-dependencies.xml +++ /dev/null @@ -1,30 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<scenario name="basic-nest"> - <step name="a"/> - <step name="aa"/> - <step name="b" requires="a"/> - <step name="f" requires="b,aa"/> - <group name="g"> - <step name="c"/> - <group name="gg" requires="c"> - <step name="d"/> - <step name="dd" requires="c"/> - <step name="e" requires="d"/> - </group> - </group> - <step name="i" requires="f,g"/> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/one-scenario.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/one-scenario.xml deleted file mode 100644 index e5cb6f29..00000000 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/one-scenario.xml +++ /dev/null @@ -1,20 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> - -<scenario name="one" description="" logDir="/tmp/junit-stc/one"> - <step name="yolo" exec="some-command args"/> - <step name="hello" exec="some-command other args" requires="yolo"/> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/scenario.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/scenario.xml deleted file mode 100644 index 533b11ea..00000000 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/scenario.xml +++ /dev/null @@ -1,54 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<scenario name="foo" description="Test Scenario" logDir="${test.dir}/foo"> - <import file="${test.dir}/one-scenario.xml" namespace="foo"/> - - <import file="${test.dir}/two-scenario.xml"/> - - <dependency name="dude" requires="~yolo"/> - - <step name="yo" exec="some-command ${HOME} and ${prop.foo} args" if="${prop.foo}"/> - <step name="hi" exec="some-command ${prop.bar} or ${HOME} other args"/> - <step name="there" exec="another-command" requires="yo,hi"/> - - <step name="maybe" exec="another-command" requires="~hi" unless="${prop.foo}"/> - - <group name="alpha" exec="same-command args" requires="yo"> - <step name="one" exec="asdads"/> - <step name="two" exec="asdads"/> - <group name="three" exec="asdads" requires="one,two"> - <step name="three.a"/> - <step name="three.b" requires="three.a"/> - <step name="three.c" requires="three.b"/> - </group> - </group> - - <dependency name="maybe" requires="yo"/> - - <parallel var="${TOC#}" requires="alpha"> - <step name="ping-${#}" exec="asdads ${TOC#}"/> - <step name="pong-${#}" exec="asdads"/> - <step name="ding-${#}" exec="asdads" requires="ping-${#},pong-${#}"/> - <dependency name="maybe" requires="ding-${#}"/> - </parallel> - - <sequential var="${TOC#}" requires="alpha" starts="fifi-${#},gigi-${#}" ends="gaga-${#-1}"> - <step name="fifi-${#}" exec="asdads ${TOC#}"/> - <step name="gigi-${#}" exec="asdads"/> - <step name="gaga-${#}" exec="asdads" requires="fifi-${#},gigi-${#}"/> - <dependency name="maybe" requires="gaga-${#}"/> - </sequential> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/simple-scenario.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/simple-scenario.xml deleted file mode 100644 index c70fe872..00000000 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/simple-scenario.xml +++ /dev/null @@ -1,26 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> -<scenario name="foo" description="Simple Test Scenario" logDir="/tmp/junit-stc/foo"> - <group name="alpha" exec="same-command args"> - <step name="one" exec="asdads"/> - <step name="two" exec="asdads"/> - <group name="three" exec="asdads" requires="one,two"> - <step name="three.a"/> - <step name="three.b" requires="three.a"/> - <step name="three.c" requires="three.b"/> - </group> - </group> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/two-scenario.xml b/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/two-scenario.xml deleted file mode 100644 index 0d6135d5..00000000 --- a/framework/src/onos/utils/stc/src/test/resources/org/onlab/stc/two-scenario.xml +++ /dev/null @@ -1,21 +0,0 @@ -<!-- - ~ Copyright 2015 Open Networking Laboratory - ~ - ~ 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. - --> - -<scenario name="two" description="" logDir="/tmp/junit-stc/two"> - <step name="dude" exec="some-command args"/> - <step name="waz" exec="some-command other args"/> - <step name="up" exec="another-command" requires="dude,waz"/> -</scenario>
\ No newline at end of file diff --git a/framework/src/onos/utils/thirdparty/pom.xml b/framework/src/onos/utils/thirdparty/pom.xml deleted file mode 100644 index d383bd60..00000000 --- a/framework/src/onos/utils/thirdparty/pom.xml +++ /dev/null @@ -1,115 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ Copyright 2014 Open Networking Laboratory - ~ - ~ 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. - --> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onosproject</groupId> - <artifactId>onlab-utils</artifactId> - <version>1.4.0-rc1</version> - <relativePath>../pom.xml</relativePath> - </parent> - - <artifactId>onlab-thirdparty</artifactId> - <packaging>bundle</packaging> - - <description>ONLab third-party dependencies</description> - - <dependencies> - <dependency> - <groupId>com.googlecode.concurrent-trees</groupId> - <artifactId>concurrent-trees</artifactId> - </dependency> - - <dependency> - <!-- FIXME once fixes get merged to upstream --> - <groupId>org.onosproject</groupId> - <artifactId>copycat-api</artifactId> - <version>${copycat.version}</version> - </dependency> - - <dependency> - <!-- FIXME once fixes get merged to upstream --> - <groupId>org.onosproject</groupId> - <artifactId>copycat-core</artifactId> - <version>${copycat.version}</version> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-shade-plugin</artifactId> - <configuration> - <createSourcesJar>true</createSourcesJar> - - <artifactSet> - <excludes> - <!-- exclude OSGi-ready transitive dependencies --> - <exclude>com.google.guava:guava</exclude> - <exclude>com.esotericsoftware:*</exclude> - <exclude>org.ow2.asm:asm</exclude> - <exclude>org.objenesis:objenesis</exclude> - <exclude>io.netty:*</exclude> - </excludes> - </artifactSet> - - <filters> - - <filter> - <artifact>com.googlecode.concurrent-trees:concurrent-trees</artifact> - <includes> - <include>com/googlecode/**</include> - </includes> - </filter> - - <filter> - <artifact>org.onosproject:copycat*</artifact> - <includes> - <include>**</include> - </includes> - </filter> - - </filters> - </configuration> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>shade</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <configuration> - <instructions> - <Export-Package> - com.googlecode.concurrenttrees.*;net.kuujo.copycat.* - </Export-Package> - </instructions> - </configuration> - </plugin> - </plugins> - </build> - -</project> diff --git a/framework/src/onos/utils/thirdparty/src/main/java/org/onlab/thirdparty/OnlabThirdparty.java b/framework/src/onos/utils/thirdparty/src/main/java/org/onlab/thirdparty/OnlabThirdparty.java deleted file mode 100644 index 217ee026..00000000 --- a/framework/src/onos/utils/thirdparty/src/main/java/org/onlab/thirdparty/OnlabThirdparty.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 Open Networking Laboratory - * - * 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.onlab.thirdparty; - - -/** - * Empty class required to get the onlab-thirdparty module to build properly. - * - * NOTE Required for shade plugin to operate. - */ -public class OnlabThirdparty { - -} |